# Table of Contents - [Introduction | Raycast API](#introduction-raycast-api) - [Create Your First Extension | Raycast API](#create-your-first-extension-raycast-api) - [Getting Started | Raycast API](#getting-started-raycast-api) - [Unknown](#unknown) - [Unknown](#unknown) - [Contribute to an Extension | Raycast API](#contribute-to-an-extension-raycast-api) - [Publish an Extension | Raycast API](#publish-an-extension-raycast-api) - [Debug an Extension | Raycast API](#debug-an-extension-raycast-api) - [Install an Extension | Raycast API](#install-an-extension-raycast-api) - [Review an Extension in a Pull Request | Raycast API](#review-an-extension-in-a-pull-request-raycast-api) - [Prepare an Extension for Store | Raycast API](#prepare-an-extension-for-store-raycast-api) - [Create an AI Extension | Raycast API](#create-an-ai-extension-raycast-api) - [Getting Started | Raycast API](#getting-started-raycast-api) - [Learn Core Concepts of AI Extensions | Raycast API](#learn-core-concepts-of-ai-extensions-raycast-api) - [Follow Best Practices for AI Extensions | Raycast API](#follow-best-practices-for-ai-extensions-raycast-api) - [Write Evals for Your AI Extension | Raycast API](#write-evals-for-your-ai-extension-raycast-api) - [Publish a Private Extension | Raycast API](#publish-a-private-extension-raycast-api) - [Collaborate on Private Extensions | Raycast API](#collaborate-on-private-extensions-raycast-api) - [Getting Started | Raycast API](#getting-started-raycast-api) - [File Structure | Raycast API](#file-structure-raycast-api) - [Doppler Share Secrets | Raycast API](#doppler-share-secrets-raycast-api) - [Hacker News | Raycast API](#hacker-news-raycast-api) - [Spotify Controls | Raycast API](#spotify-controls-raycast-api) - [Terminology | Raycast API](#terminology-raycast-api) - [Deeplinks | Raycast API](#deeplinks-raycast-api) - [Todo List | Raycast API](#todo-list-raycast-api) - [Lifecycle | Raycast API](#lifecycle-raycast-api) - [Arguments | Raycast API](#arguments-raycast-api) - [Background Refresh | Raycast API](#background-refresh-raycast-api) - [Manage Extensions Command | Raycast API](#manage-extensions-command-raycast-api) - [Versioning | Raycast API](#versioning-raycast-api) - [Manifest | Raycast API](#manifest-raycast-api) - [CLI | Raycast API](#cli-raycast-api) - [Security | Raycast API](#security-raycast-api) - [Best Practices | Raycast API](#best-practices-raycast-api) - [Tool | Raycast API](#tool-raycast-api) - [VS Code (community tool) | Raycast API](#vs-code-community-tool-raycast-api) - [Browser Extension | Raycast API](#browser-extension-raycast-api) - [Developer Tools | Raycast API](#developer-tools-raycast-api) - [Preferences | Raycast API](#preferences-raycast-api) - [Forked Extensions (community tool) | Raycast API](#forked-extensions-community-tool-raycast-api) - [HUD | Raycast API](#hud-raycast-api) - [Command | Raycast API](#command-raycast-api) - [Alert | Raycast API](#alert-raycast-api) - [Raycast Window & Search Bar | Raycast API](#raycast-window-search-bar-raycast-api) - [getAvatarIcon | Raycast API](#getavataricon-raycast-api) - [Cache | Raycast API](#cache-raycast-api) - [Environment | Raycast API](#environment-raycast-api) - [Clipboard | Raycast API](#clipboard-raycast-api) - [Functions | Raycast API](#functions-raycast-api) - [Storage | Raycast API](#storage-raycast-api) - [Feedback | Raycast API](#feedback-raycast-api) - [Keyboard | Raycast API](#keyboard-raycast-api) - [runPowerShellScript | Raycast API](#runpowershellscript-raycast-api) - [executeSQL | Raycast API](#executesql-raycast-api) - [withCache | Raycast API](#withcache-raycast-api) - [Toast | Raycast API](#toast-raycast-api) - [ESLint | Raycast API](#eslint-raycast-api) - [showFailureToast | Raycast API](#showfailuretoast-raycast-api) - [getProgressIcon | Raycast API](#getprogressicon-raycast-api) - [Window Management | Raycast API](#window-management-raycast-api) - [getFavicon | Raycast API](#getfavicon-raycast-api) - [System Utilities | Raycast API](#system-utilities-raycast-api) - [Icons | Raycast API](#icons-raycast-api) - [createDeeplink | Raycast API](#createdeeplink-raycast-api) - [runAppleScript | Raycast API](#runapplescript-raycast-api) - [User Interface | Raycast API](#user-interface-raycast-api) - [AI | Raycast API](#ai-raycast-api) - [OAuth Utils | Raycast API](#oauth-utils-raycast-api) - [getAccessToken | Raycast API](#getaccesstoken-raycast-api) - [Navigation | Raycast API](#navigation-raycast-api) - [Getting a Google client ID | Raycast API](#getting-a-google-client-id-raycast-api) - [withAccessToken | Raycast API](#withaccesstoken-raycast-api) - [Templates | Raycast API](#templates-raycast-api) - [Menu Bar Commands | Raycast API](#menu-bar-commands-raycast-api) - [Action Panel | Raycast API](#action-panel-raycast-api) - [FAQ | Raycast API](#faq-raycast-api) - [v1.42.0 | Raycast API](#v1-42-0-raycast-api) - [v1.51.0 | Raycast API](#v1-51-0-raycast-api) - [Migration | Raycast API](#migration-raycast-api) - [Colors | Raycast API](#colors-raycast-api) - [v1.50.0 | Raycast API](#v1-50-0-raycast-api) - [React hooks | Raycast API](#react-hooks-raycast-api) - [v1.31.0 | Raycast API](#v1-31-0-raycast-api) - [useCachedState | Raycast API](#usecachedstate-raycast-api) - [Detail | Raycast API](#detail-raycast-api) - [v1.48.8 | Raycast API](#v1-48-8-raycast-api) - [OAuthService | Raycast API](#oauthservice-raycast-api) - [v1.59.0 | Raycast API](#v1-59-0-raycast-api) - [useLocalStorage | Raycast API](#uselocalstorage-raycast-api) - [useAI | Raycast API](#useai-raycast-api) - [v1.37.0 | Raycast API](#v1-37-0-raycast-api) - [useFrecencySorting | Raycast API](#usefrecencysorting-raycast-api) - [v1.28.0 | Raycast API](#v1-28-0-raycast-api) - [useForm | Raycast API](#useform-raycast-api) - [OAuth | Raycast API](#oauth-raycast-api) - [useSQL | Raycast API](#usesql-raycast-api) - [usePromise | Raycast API](#usepromise-raycast-api) - [Getting Started | Raycast API](#getting-started-raycast-api) - [useStreamJSON | Raycast API](#usestreamjson-raycast-api) - [useExec | Raycast API](#useexec-raycast-api) - [useFetch | Raycast API](#usefetch-raycast-api) --- # Introduction | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/readme.md) . Welcome, developers! Our docs cover guides, examples, references, and more to help you build extensions and share them with [our community](https://raycast.com/community) and [your team](https://developers.raycast.com/teams/getting-started) . ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-8a4f81b2b9ccaf142983dad7a0c7a2ce953467d5%252Fintroduction-hello-world.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=d1796f36&sv=2) The Raycast Platform consists of two parts: * **API:** This allows developers to build rich extensions with React, Node.js, and TypeScript. The docs explain how to use the API to build top-notch experiences. * **Store:** This lets developers share their extensions with all Raycast users. You'll learn how to [publish your extension](https://developers.raycast.com/basics/publish-an-extension) . [](https://developers.raycast.com/#key-features) Key features ------------------------------------------------------------------ Here are a few points that make our ecosystem special: * **Powerful and familiar tooling:** Extensions are built with TypeScript, React, and Node. Leverage npm's ecosystem to quickly build what you imagine. * **No-brainer to build UI:** You concentrate on the logic, we push the pixels. Use our built-in UI components to be consistent with all our extensions. * **Collaborate with our community:** Build your extension, share it with our community, and get inspired by others. * **Developer experience front and foremost:** A strongly typed API, hot-reloading, and modern tooling that makes it a blast to work with. * **Easy to start, flexible to scale:** Start with a simple script, add a static UI or use React to go wild. Anything goes. [](https://developers.raycast.com/#overview) Overview ---------------------------------------------------------- A quick overview about where to find what in our docs: * [**Basics:**](https://developers.raycast.com/basics/getting-started) Go over this section to learn how to build extensions in our step-by-step guides. * [**Teams:**](https://developers.raycast.com/teams/getting-started) Build and share extensions with your teammates to speed up common workflows. * [**Examples:**](https://developers.raycast.com/examples/doppler) Kickstart your extension by using an open-source example and learn as you go. * [**Information:**](https://developers.raycast.com/information/best-practices) Get the background knowledge to master your understanding of our platform. * [**API Reference:**](https://developers.raycast.com/api-reference/ai) Go into details with the API reference that includes code snippets. * [**Utilities:**](https://developers.raycast.com/utilities/getting-started) A set of utilities to streamline common patterns and operations used in extensions. Now, let's build πŸ’ͺ [NextGetting Started](https://developers.raycast.com/basics/getting-started) Last updated 1 year ago --- # Create Your First Extension | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/basics/create-your-first-extension.md) . [](https://developers.raycast.com/basics/create-your-first-extension#create-a-new-extension) Create a new extension ------------------------------------------------------------------------------------------------------------------------ Open the Create Extension command, name your extension "Hello World" and select the "Detail" template. Pick a parent folder in the Location field and press `⌘` `↡` to continue. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-3cf0d0478508eca468e31c4f9ee871ea269d71e4%252Fhello-world.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=38503a8b&sv=2) Create Extension command in Raycast To create a private extension, select your organization in the first dropdown. You need to be logged in and part of an organization to see the dropdown. Learn more about Raycast for Teams [here](https://developers.raycast.com/teams/getting-started) . To kickstart your extensions, Raycast provides various templates for commands and tools. Learn more [here](https://developers.raycast.com/information/developer-tools/templates) . Next, you'll need to follow the on-screen instructions to build the extension. [](https://developers.raycast.com/basics/create-your-first-extension#build-the-extension) Build the extension ------------------------------------------------------------------------------------------------------------------ Open your terminal, navigate to your extension directory and run `npm install && npm run dev`. Open Raycast, and you'll notice your extension at the top of the root search. Press `↡` to open it. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-2927c54a56a87fd95fb0340b9acfcd26f48f0f40%252Fhello-world-2.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=1a3dd2d1&sv=2) Your first extension [](https://developers.raycast.com/basics/create-your-first-extension#develop-your-extension) Develop your extension ------------------------------------------------------------------------------------------------------------------------ To make changes to your extension, open the `./src/index.tsx` file in your extension directory, change the `markdown` text and save it. Then, open your command in Raycast again and see your changes. `npm run dev` starts the extension in development mode with hot reloading, error reporting and [more](https://developers.raycast.com/information/developer-tools/cli#development) . [](https://developers.raycast.com/basics/create-your-first-extension#use-your-extension) Use your extension ---------------------------------------------------------------------------------------------------------------- Now, you can press `βŒƒ` `C` in your terminal to stop `npm run dev`. The extension stays in Raycast, and you can find its commands in the root when searching for the extension name "Hello World" or the command name "Render Markdown". ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-2927c54a56a87fd95fb0340b9acfcd26f48f0f40%252Fhello-world-2.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=1a3dd2d1&sv=2) Find your extension in the root search πŸŽ‰ Congratulations! You built your first extension. Off to many more. Don't forget to run [`npm run dev`](https://developers.raycast.com/information/developer-tools/cli#development) again when you want to change something in your extension. [PreviousGetting Started](https://developers.raycast.com/basics/getting-started) [NextContribute to an Extension](https://developers.raycast.com/basics/contribute-to-an-extension) Last updated 1 year ago --- # Getting Started | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/basics/getting-started.md) . [](https://developers.raycast.com/basics/getting-started#system-requirements) System Requirements ------------------------------------------------------------------------------------------------------ Before you can create your first extension, make sure you have the following prerequisites. * You have Raycast 1.26.0 or higher installed. * You have [Node.js](https://nodejs.org/) 22.14 or higher installed. We recommend [nvm](https://github.com/nvm-sh/nvm) to install Node. * You have [npm](http://npmjs.com/) 7 or higher * You are familiar with [React](https://reactjs.org/) and [TypeScript](https://www.typescriptlang.org/) . Don't worry, you don't need to be an expert. If you need some help with the basics, check out TypeScript's [Handbook](https://www.typescriptlang.org/docs/handbook/intro.html) and React's [Getting Started](https://react.dev/learn) guide. [](https://developers.raycast.com/basics/getting-started#sign-in) Sign In ------------------------------------------------------------------------------ ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-829557d913eae5961c97c1493babd3e6371a30f1%252Fwelcome.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=4ec9b461&sv=2) Opening the "Store" command in Raycast You need to be signed in to use the following extension development commands. * **Store:** Search and install all published extensions * **Create Extension:** Create new extensions from templates * **Import Extension:** Import extensions from source code * **Manage Extensions**: List and edit your published extensions [PreviousIntroduction](https://developers.raycast.com/) [NextCreate Your First Extension](https://developers.raycast.com/basics/create-your-first-extension) Last updated 1 year ago * [System Requirements](https://developers.raycast.com/basics/getting-started#system-requirements) * [Sign In](https://developers.raycast.com/basics/getting-started#sign-in) --- # Unknown \# Raycast API ## Raycast API - \[Introduction\](https://developers.raycast.com/readme.md): Start building your perfect tools with the Raycast API. - \[Getting Started\](https://developers.raycast.com/basics/getting-started.md): This guide covers the prerequisites you need to start building extensions. - \[Create Your First Extension\](https://developers.raycast.com/basics/create-your-first-extension.md): Learn how to build your first extension and use it in Raycast. - \[Contribute to an Extension\](https://developers.raycast.com/basics/contribute-to-an-extension.md): Learn how to import an extension to collaborate with others. - \[Prepare an Extension for Store\](https://developers.raycast.com/basics/prepare-an-extension-for-store.md): Learn how to get through review process quickly - \[Publish an Extension\](https://developers.raycast.com/basics/publish-an-extension.md): Learn how to share your extension with our community. - \[Debug an Extension\](https://developers.raycast.com/basics/debug-an-extension.md): This guide covers how to find and fix bugs in your extension. - \[Install an Extension\](https://developers.raycast.com/basics/install-an-extension.md): Learn how to find and use extensions from the Raycast Store. - \[Review an Extension in a Pull Request\](https://developers.raycast.com/basics/review-pullrequest.md): Learn how to review a contribution from a Pull Request opened by a contributor. - \[Getting Started\](https://developers.raycast.com/ai/getting-started.md): This guide explains how to use AI inside extensions. - \[Create an AI Extension\](https://developers.raycast.com/ai/create-an-ai-extension.md): Learn how to turn a regular extension into an AI-powered one. - \[Learn Core Concepts of AI Extensions\](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions.md): Get to know the core concepts of AI extensions. - \[Write Evals for Your AI Extension\](https://developers.raycast.com/ai/write-evals-for-your-ai-extension.md): Make your AI Extension more reliable by writing evals. - \[Follow Best Practices for AI Extensions\](https://developers.raycast.com/ai/follow-best-practices-for-ai-extensions.md): Make the most out of your AI Extension by following best practices. - \[Getting Started\](https://developers.raycast.com/teams/getting-started.md): This guide sets you up with Raycast for Teams. - \[Publish a Private Extension\](https://developers.raycast.com/teams/publish-a-private-extension.md): Learn how to share an extension in your organization's private extension store - \[Collaborate on Private Extensions\](https://developers.raycast.com/teams/collaborate-on-private-extensions.md): This guide explains how to collaborate with your team on extensions. - \[Doppler Share Secrets\](https://developers.raycast.com/examples/doppler.md): This example uses a simple form to collect data. - \[Hacker News\](https://developers.raycast.com/examples/hacker-news.md): This example shows how to show an RSS feed as a List. - \[Todo List\](https://developers.raycast.com/examples/todo-list.md): This example show how to use lists in combination with forms. - \[Spotify Controls\](https://developers.raycast.com/examples/spotify-controls.md): This example shows how to bundle multiple scripts into a single extension. - \[Terminology\](https://developers.raycast.com/information/terminology.md): An explanation of various terms used in this documentation. - \[File Structure\](https://developers.raycast.com/information/file-structure.md): Understand the file structure of an extension. - \[Manifest\](https://developers.raycast.com/information/manifest.md) - \[Lifecycle\](https://developers.raycast.com/information/lifecycle.md) - \[Arguments\](https://developers.raycast.com/information/lifecycle/arguments.md) - \[Background Refresh\](https://developers.raycast.com/information/lifecycle/background-refresh.md) - \[Deeplinks\](https://developers.raycast.com/information/lifecycle/deeplinks.md) - \[Best Practices\](https://developers.raycast.com/information/best-practices.md): Tips to guarantee a good user experience for your extensions. - \[Developer Tools\](https://developers.raycast.com/information/developer-tools.md) - \[Manage Extensions Command\](https://developers.raycast.com/information/developer-tools/manage-extensions-command.md): A Raycast command to manage your extensions, add new commands or attachments, etc. - \[CLI\](https://developers.raycast.com/information/developer-tools/cli.md): The Raycast CLI allows you to build, develop, and lint your extension. - \[ESLint\](https://developers.raycast.com/information/developer-tools/eslint.md) - \[Forked Extensions (community tool)\](https://developers.raycast.com/information/developer-tools/forked-extensions.md) - \[VS Code (community tool)\](https://developers.raycast.com/information/developer-tools/vscode.md) - \[Templates\](https://developers.raycast.com/information/developer-tools/templates.md): Learn about the templates provided by Raycast to help kickstart your extension. - \[Security\](https://developers.raycast.com/information/security.md) - \[Versioning\](https://developers.raycast.com/information/versioning.md) - \[AI\](https://developers.raycast.com/api-reference/ai.md) - \[Browser Extension\](https://developers.raycast.com/api-reference/browser-extension.md) - \[Cache\](https://developers.raycast.com/api-reference/cache.md) - \[Command\](https://developers.raycast.com/api-reference/command.md) - \[Clipboard\](https://developers.raycast.com/api-reference/clipboard.md) - \[Environment\](https://developers.raycast.com/api-reference/environment.md) - \[Feedback\](https://developers.raycast.com/api-reference/feedback.md) - \[Alert\](https://developers.raycast.com/api-reference/feedback/alert.md) - \[HUD\](https://developers.raycast.com/api-reference/feedback/hud.md) - \[Toast\](https://developers.raycast.com/api-reference/feedback/toast.md) - \[Keyboard\](https://developers.raycast.com/api-reference/keyboard.md) - \[Menu Bar Commands\](https://developers.raycast.com/api-reference/menu-bar-commands.md) - \[OAuth\](https://developers.raycast.com/api-reference/oauth.md) - \[Preferences\](https://developers.raycast.com/api-reference/preferences.md) - \[Storage\](https://developers.raycast.com/api-reference/storage.md) - \[System Utilities\](https://developers.raycast.com/api-reference/utilities.md) - \[User Interface\](https://developers.raycast.com/api-reference/user-interface.md) - \[Action Panel\](https://developers.raycast.com/api-reference/user-interface/action-panel.md) - \[Actions\](https://developers.raycast.com/api-reference/user-interface/actions.md) - \[Detail\](https://developers.raycast.com/api-reference/user-interface/detail.md) - \[Form\](https://developers.raycast.com/api-reference/user-interface/form.md) - \[List\](https://developers.raycast.com/api-reference/user-interface/list.md): The de-facto user interface in Raycast. Ideal to present similar data such as to-dos or files. - \[Grid\](https://developers.raycast.com/api-reference/user-interface/grid.md) - \[Colors\](https://developers.raycast.com/api-reference/user-interface/colors.md) - \[Icons & Images\](https://developers.raycast.com/api-reference/user-interface/icons-and-images.md) - \[Navigation\](https://developers.raycast.com/api-reference/user-interface/navigation.md) - \[Raycast Window & Search Bar\](https://developers.raycast.com/api-reference/window-and-search-bar.md) - \[Tool\](https://developers.raycast.com/api-reference/tool.md) - \[Window Management\](https://developers.raycast.com/api-reference/window-management.md) - \[Getting Started\](https://developers.raycast.com/utilities/getting-started.md) - \[Functions\](https://developers.raycast.com/utilities/functions.md) - \[createDeeplink\](https://developers.raycast.com/utilities/functions/createdeeplink.md) - \[executeSQL\](https://developers.raycast.com/utilities/functions/executesql.md) - \[runAppleScript\](https://developers.raycast.com/utilities/functions/runapplescript.md) - \[runPowerShellScript\](https://developers.raycast.com/utilities/functions/runpowershellscript.md) - \[showFailureToast\](https://developers.raycast.com/utilities/functions/showfailuretoast.md) - \[withCache\](https://developers.raycast.com/utilities/functions/withcache.md) - \[Icons\](https://developers.raycast.com/utilities/icons.md) - \[getAvatarIcon\](https://developers.raycast.com/utilities/icons/getavataricon.md) - \[getFavicon\](https://developers.raycast.com/utilities/icons/getfavicon.md) - \[getProgressIcon\](https://developers.raycast.com/utilities/icons/getprogressicon.md) - \[OAuth Utils\](https://developers.raycast.com/utilities/oauth.md) - \[OAuthService\](https://developers.raycast.com/utilities/oauth/oauthservice.md) - \[withAccessToken\](https://developers.raycast.com/utilities/oauth/withaccesstoken.md) - \[getAccessToken\](https://developers.raycast.com/utilities/oauth/getaccesstoken.md) - \[Getting a Google client ID\](https://developers.raycast.com/utilities/oauth/getting-google-client-id.md) - \[React hooks\](https://developers.raycast.com/utilities/react-hooks.md) - \[useCachedState\](https://developers.raycast.com/utilities/react-hooks/usecachedstate.md) - \[usePromise\](https://developers.raycast.com/utilities/react-hooks/usepromise.md) - \[useCachedPromise\](https://developers.raycast.com/utilities/react-hooks/usecachedpromise.md) - \[useFetch\](https://developers.raycast.com/utilities/react-hooks/usefetch.md) - \[useForm\](https://developers.raycast.com/utilities/react-hooks/useform.md) - \[useExec\](https://developers.raycast.com/utilities/react-hooks/useexec.md) - \[useSQL\](https://developers.raycast.com/utilities/react-hooks/usesql.md) - \[useAI\](https://developers.raycast.com/utilities/react-hooks/useai.md) - \[useFrecencySorting\](https://developers.raycast.com/utilities/react-hooks/usefrecencysorting.md) - \[useStreamJSON\](https://developers.raycast.com/utilities/react-hooks/usestreamjson.md) - \[useLocalStorage\](https://developers.raycast.com/utilities/react-hooks/uselocalstorage.md) - \[Changelog\](https://developers.raycast.com/misc/changelog.md) - \[Migration\](https://developers.raycast.com/misc/migration.md) - \[v1.28.0\](https://developers.raycast.com/misc/migration/v1.28.0.md) - \[v1.31.0\](https://developers.raycast.com/misc/migration/v1.31.0.md) - \[v1.37.0\](https://developers.raycast.com/misc/migration/v1.37.0.md) - \[v1.42.0\](https://developers.raycast.com/misc/migration/v1.42.0.md) - \[v1.48.8\](https://developers.raycast.com/misc/migration/v1.48.8.md) - \[v1.50.0\](https://developers.raycast.com/misc/migration/v1.50.0.md) - \[v1.51.0\](https://developers.raycast.com/misc/migration/v1.51.0.md) - \[v1.59.0\](https://developers.raycast.com/misc/migration/v1.59.0.md) - \[FAQ\](https://developers.raycast.com/misc/faq.md): Answers to the most frequently asked questions. --- # Agent Instructions This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. ## Querying This Documentation If you need additional information, you can query the documentation dynamically by asking a question. Perform an HTTP GET request on a page URL with the \`ask\` query parameter: \`\`\` GET https://developers.raycast.com/readme.md?ask= \`\`\` The question should be specific, self-contained, and written in natural language. The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. --- # Unknown \> For the complete documentation index, see \[llms.txt\](https://developers.raycast.com/llms.txt). Markdown versions of documentation pages are available by appending \`.md\` to page URLs; this page is available as \[Markdown\](https://developers.raycast.com/readme.md). # Introduction Welcome, developers! Our docs cover guides, examples, references, and more to help you build extensions and share them with \[our community\](https://raycast.com/community) and \[your team\](/teams/getting-started.md). !\[\](/files/ZsS9KGMtcehM70c2tUwC) The Raycast Platform consists of two parts: \* \*\*API:\*\* This allows developers to build rich extensions with React, Node.js, and TypeScript. The docs explain how to use the API to build top-notch experiences. \* \*\*Store:\*\* This lets developers share their extensions with all Raycast users. You'll learn how to \[publish your extension\](/basics/publish-an-extension.md). ## Key features Here are a few points that make our ecosystem special: \* \*\*Powerful and familiar tooling:\*\* Extensions are built with TypeScript, React, and Node. Leverage npm's ecosystem to quickly build what you imagine. \* \*\*No-brainer to build UI:\*\* You concentrate on the logic, we push the pixels. Use our built-in UI components to be consistent with all our extensions. \* \*\*Collaborate with our community:\*\* Build your extension, share it with our community, and get inspired by others. \* \*\*Developer experience front and foremost:\*\* A strongly typed API, hot-reloading, and modern tooling that makes it a blast to work with. \* \*\*Easy to start, flexible to scale:\*\* Start with a simple script, add a static UI or use React to go wild. Anything goes. ## Overview A quick overview about where to find what in our docs: \* \[\*\*Basics:\*\*\](/basics/getting-started.md) Go over this section to learn how to build extensions in our step-by-step guides. \* \[\*\*Teams:\*\*\](/teams/getting-started.md) Build and share extensions with your teammates to speed up common workflows. \* \[\*\*Examples:\*\*\](/examples/doppler.md) Kickstart your extension by using an open-source example and learn as you go. \* \[\*\*Information:\*\*\](/information/best-practices.md) Get the background knowledge to master your understanding of our platform. \* \[\*\*API Reference:\*\*\](/api-reference/ai.md) Go into details with the API reference that includes code snippets. \* \[\*\*Utilities:\*\*\](/utilities/getting-started.md) A set of utilities to streamline common patterns and operations used in extensions. Now, let's build πŸ’ͺ --- # Agent Instructions This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com. ## Querying This Documentation If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question. Perform an HTTP GET request on the current page URL with the \`ask\` query parameter, and the optional \`goal\` query parameter: \`\`\` GET https://developers.raycast.com/readme.md?ask=&goal= \`\`\` \`ask\` is the immediate question: it should be specific, self-contained, and written in natural language. \`goal\` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal. The response will contain a direct answer to the question and relevant excerpts and sources from the documentation. Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections. --- # Contribute to an Extension | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/basics/contribute-to-an-extension.md) . All published extensions are open-source and can be found in [this repository](https://github.com/raycast/extensions) . This makes it easy for multiple developers to collaborate. This guide explains how to import an extension in order to fix a bug, add a new feature or otherwise contribute to it. [](https://developers.raycast.com/basics/contribute-to-an-extension#get-source-code) Get source code --------------------------------------------------------------------------------------------------------- First, you need to find the source code of the extension. The easiest way to do this is to use the `Fork Extension` action in the Raycast's root search. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-d8248b215be20ea329b284134cce26609fb91dde%252Ffork-extension.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=f80ce996&sv=2) Fork an extension [](https://developers.raycast.com/basics/contribute-to-an-extension#develop-the-extension) Develop the extension --------------------------------------------------------------------------------------------------------------------- After you have the source code locally, open the Terminal and navigate to the extension's folder. Once there, run `npm install && npm run dev` from the extension folder in your Terminal to start developing the extension. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-d93798084581d66e02d4e51c48bb8c6edd66709d%252Fbasics-open-command.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=6a381d7&sv=2) Open imported extension ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-64a3aa26124f0f72eab167839b9858c06e41e84b%252Fbasics-icon-list.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=140350f6&sv=2) Icon list command You should see your forked extension at the top of your root search and can open its commands. When you're done editing the extension, make sure to add yourself to the contributors section of its [manifest](https://developers.raycast.com/information/manifest#extension-properties) . If you used the `Fork Extension` action, this should have happened automatically. Additionally, ensure the `CHANGELOG.md` file is updated with your changes; create it if it doesn't exist. Use the `{PR_MERGE_DATE}` placeholder for the date – see the [Version History documentation](https://developers.raycast.com/basics/prepare-an-extension-for-store#version-history) for details. Once everything is ready, see [how to publish an extension](https://developers.raycast.com/basics/publish-an-extension) for instructions on validating and publishing the changes. [PreviousCreate Your First Extension](https://developers.raycast.com/basics/create-your-first-extension) [NextPrepare an Extension for Store](https://developers.raycast.com/basics/prepare-an-extension-for-store) Last updated 10 months ago * [Get source code](https://developers.raycast.com/basics/contribute-to-an-extension#get-source-code) * [Develop the extension](https://developers.raycast.com/basics/contribute-to-an-extension#develop-the-extension) --- # Publish an Extension | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/basics/publish-an-extension.md) . Before you publish your extension, take a look at [how to prepare your extension](https://developers.raycast.com/basics/prepare-an-extension-for-store) for the Store. Making sure you follow the guidelines is the best way to help your extension pass the review. ### [](https://developers.raycast.com/basics/publish-an-extension#validate-your-extension) Validate your extension Open your terminal, navigate to your extension directory, and run `npm run build` to verify your extension. The command should complete without any errors. `npm run build` validates your extension for distribution without publishing it to the store. Read more about it [here](https://developers.raycast.com/information/developer-tools/cli#build) . ### [](https://developers.raycast.com/basics/publish-an-extension#publish-your-extension) Publish your extension To share your extension with others, navigate to your extension directory, and run `npm run publish` to publish your extension. It is possible that the `publish` script doesn't exist (usually because the extension was created before the template was updated to include it). In that case, you can add the following line in the `scripts` object of the package.json `"publish": "npx @raycast/api@latest publish"` and then run `npm run publish` again. You will be asked to authenticate with GitHub because the script will automatically open a pull request in our [`raycast/extensions`](https://github.com/raycast/extensions) repository. The command will squash commits and their commit messages. If you want more control, see the [alternative way](https://developers.raycast.com/basics/publish-an-extension#alternative-way) below. If someone contributes to your extension, or you make edits directly on GitHub, running `npm run publish` will fail until you run Copy npx @raycast/api@latest pull-contributions in your git repository. This will merge the contributions with your code, asking you to fix the conflicts if any. Once the pull request is opened, you can continue pushing more commits to it by running `npm run publish` again. #### [](https://developers.raycast.com/basics/publish-an-extension#alternative-way) Alternative way If you want more control over the publishing process, you can manually do what `npm run publish` does. You need to open a pull request in our [repository](https://github.com/raycast/extensions) . For this, [fork our repository](https://docs.github.com/en/get-started/quickstart/fork-a-repo) , add your extension to your fork, push your changes, and open a pull request [via the GitHub web interface](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) into our `main` branch. ### [](https://developers.raycast.com/basics/publish-an-extension#waiting-for-review) Waiting for review After you opened a pull request, we'll review your extension and request changes when required. Once accepted, the pull request is merged and your extension will be automatically published to the [Raycast Store](https://raycast.com/store) . We're still figuring things out and updating our guidelines. If something is unclear, please tell us in [our community](https://raycast.com/community) . ### [](https://developers.raycast.com/basics/publish-an-extension#share-your-extension) Share your extension Once your extension is published in the Raycast Store, you can share it with our community. Open the Manage Extensions command, search for your extension and press `⌘` `βŒ₯` `.` to copy the link. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-ce1f47d3a92c1377fa2cb9ace2eb4bee7cfaa58b%252Fbasics-manage-extensions.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=d73e695c&sv=2) Manage your extensions πŸš€ Now it's time to share your work! Tweet about your extension, share it with our [Slack community](https://raycast.com/community) or send it to your teammates. [PreviousPrepare an Extension for Store](https://developers.raycast.com/basics/prepare-an-extension-for-store) [NextDebug an Extension](https://developers.raycast.com/basics/debug-an-extension) Last updated 6 months ago * [Validate your extension](https://developers.raycast.com/basics/publish-an-extension#validate-your-extension) * [Publish your extension](https://developers.raycast.com/basics/publish-an-extension#publish-your-extension) * [Waiting for review](https://developers.raycast.com/basics/publish-an-extension#waiting-for-review) * [Share your extension](https://developers.raycast.com/basics/publish-an-extension#share-your-extension) --- # Debug an Extension | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/basics/debug-an-extension.md) . Bugs are unavoidable. Therefore it's important to have an easy way to discover and fix them. This guide shows you how to find problems in your extensions. [](https://developers.raycast.com/basics/debug-an-extension#console) Console --------------------------------------------------------------------------------- Use the `console` for simple debugging such as logging variables, function calls, or other helpful messages. All logs are shown in the terminal during [development mode](https://developers.raycast.com/information/developer-tools/cli#development) . Here are a few examples: Copy console.log("Hello World"); // Prints: Hello World const name = "Thomas"; console.debug(`Hello ${name}`); // Prints: Hello Thomas const error = new Error("Boom πŸ’₯"); console.error(error); // Prints: Boom πŸ’₯ For more, checkout the [Node.js documentation](https://nodejs.org/docs/latest-v22.x/api/console.html) . We automatically disable console logging for store extensions. [](https://developers.raycast.com/basics/debug-an-extension#visual-studio-code) Visual Studio Code ------------------------------------------------------------------------------------------------------- For more complex debugging you can install the [VSCode extension](https://marketplace.visualstudio.com/items?itemName=tonka3000.raycast) to be able to attach a node.js debugger to the running Raycast session. 1. Activate your extension in dev mode via `npm run dev` or via the VSCode command `Raycast: Start Development Mode` 2. Start the VSCode command `Raycast: Attach Debugger` 3. Set your breakpoint like in any other node.js base project 4. Activate your command [](https://developers.raycast.com/basics/debug-an-extension#unhandled-exceptions-and-promise-rejections) Unhandled exceptions and Promise rejections --------------------------------------------------------------------------------------------------------------------------------------------------------- All unhandled exceptions and Promise rejections are shown with an error overlay in Raycast. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-b5a9bcaeefa6d23c38427b21408ffd98953722ef%252Fbasics-unhandled-exception.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=8a712328&sv=2) Unhandled exception in development mode During development, we show the stack trace and add an action to jump to the error to make it easy to fix it. In production, only the error message is shown. You should [show a toast](https://developers.raycast.com/api-reference/feedback/toast#showtoast) for all expected errors, e.g. a failing network request. ### [](https://developers.raycast.com/basics/debug-an-extension#extension-issue-dashboard) Extension Issue Dashboard When unhandled exceptions and Promise rejections occur in the production build of a public extension, Raycast tries to redact all potentially sensitive information they may include, and reports them to our error backend. As an extension author, or as the manager of an organisation, you can view and manage error reports for your public extensions by going to https://www.raycast.com/extension-issues, or by finding your extension in Raycast's root, `Store` command, or `Manage Extensions` command, and using the `View Issues` action. The dashboard should give you an overview of what issues occurred, how many times, how many users were affected, and more. Each issue additionally has a detail view, including a stack trace, breadcrumbs (typically the actions performed before the crash), extension release date, Raycast version, macOS version. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-e3c7a6de170fa071b3e0caf1ac8f93d283255a91%252Fextension-issues.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=386ba1d0&sv=2) Extension Issues [](https://developers.raycast.com/basics/debug-an-extension#react-developer-tools) React Developer Tools ------------------------------------------------------------------------------------------------------------- We support [React Developer Tools](https://github.com/facebook/react/tree/main/packages/react-devtools) out-of-the-box. Use the tools to inspect and change the props of your React components, and see the results immediately in Raycast. This is especially useful for complex commands with a lot of states. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-1f048664863696612821b23b146e8b134818b54d%252Fbasics-react-developer-tools.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=a167cba8&sv=2) React Developer Tools To get started, add the `react-devtools` to your extension. Open a terminal, navigate to your extension directory and run the following command: Then re-build your extension with `npm run dev`, open the command you want to debug in Raycast, and launch the React Developer Tools with `⌘` `βŒ₯` `D`. Now select one of the React components, change a prop in the right sidebar, and hit enter. You'll notice the change immediately in Raycast. ### [](https://developers.raycast.com/basics/debug-an-extension#alternative-global-installation-of-react-developer-tools) Alternative: Global installation of React Developer Tools If you prefer to install the `react-devtools` globally, you can do the following: Then you can run `react-devtools` from a terminal to launch the standalone DevTools app. Raycast connects automatically, and you can start debugging your component tree. [](https://developers.raycast.com/basics/debug-an-extension#environments) Environments ------------------------------------------------------------------------------------------- By default, extensions installed from the store run in Node production mode and development extensions in development mode. In development mode, the CLI output shows you additional errors and warnings (e.g. the infamous warning when you're missing the React `key` property for your list items); performance is generally better when running in production mode. You can force development extensions to run in Node production mode by going to Raycast Preferences > Advanced > "Use Node production environment". At runtime, you can check which Node environment you're running in: To check whether you're running the store or local development version: [PreviousPublish an Extension](https://developers.raycast.com/basics/publish-an-extension) [NextInstall an Extension](https://developers.raycast.com/basics/install-an-extension) Last updated 6 months ago * [Console](https://developers.raycast.com/basics/debug-an-extension#console) * [Visual Studio Code](https://developers.raycast.com/basics/debug-an-extension#visual-studio-code) * [Unhandled exceptions and Promise rejections](https://developers.raycast.com/basics/debug-an-extension#unhandled-exceptions-and-promise-rejections) * [Extension Issue Dashboard](https://developers.raycast.com/basics/debug-an-extension#extension-issue-dashboard) * [React Developer Tools](https://developers.raycast.com/basics/debug-an-extension#react-developer-tools) * [Alternative: Global installation of React Developer Tools](https://developers.raycast.com/basics/debug-an-extension#alternative-global-installation-of-react-developer-tools) * [Environments](https://developers.raycast.com/basics/debug-an-extension#environments) Copy npm install --save-dev react-devtools@6.1.1 Copy npm install -g react-devtools@6.1.1 Copy if (process.env.NODE_ENV === "development") { // running in development Node environment } Copy import { environment } from "@raycast/api"; if (environment.isDevelopment) { // running the development version } --- # Install an Extension | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/basics/install-an-extension.md) . All published extensions are discoverable in the Raycast Store. Use the [web interface](https://raycast.com/store) or the Store command to find what you're looking for. [](https://developers.raycast.com/basics/install-an-extension#in-app-store) In-app Store --------------------------------------------------------------------------------------------- The easiest way to discover extensions is the in-app store. Open the Store command in Raycast and search for an extension. Press `⌘` `↡` to install the selected extension or press `↡` to see more details about it. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-61b0b1e3be8f41d44c9b3b7464a431b43824bd03%252Fbasics-inapp-store.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=d18733f7&sv=2) Store in Raycast [](https://developers.raycast.com/basics/install-an-extension#web-store) Web Store --------------------------------------------------------------------------------------- Alternatively, you can use our [web store](https://raycast.com/store) . Press `⌘` `K` to open the command palette, search for an extension and open it. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-4734fd8f31c97bb29fffbe7be8b532ad55214512%252Fbasics-web-store.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=58737c59&sv=2) Web Store Then press the Install Extension button in the top right corner and follow the steps in Raycast. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-0a6cb5bb4070227ee51ef3e30ab727e23e22f0e3%252Fbasics-install-extension.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=647993a2&sv=2) Install extension from the Web Store [](https://developers.raycast.com/basics/install-an-extension#use-installed-extensions) Use installed extensions --------------------------------------------------------------------------------------------------------------------- After an extension is installed, you can search for its commands in the root search. The extension can be further configured in the Extensions preferences tab. [PreviousDebug an Extension](https://developers.raycast.com/basics/debug-an-extension) [NextReview an Extension in a Pull Request](https://developers.raycast.com/basics/review-pullrequest) Last updated 1 year ago * [In-app Store](https://developers.raycast.com/basics/install-an-extension#in-app-store) * [Web Store](https://developers.raycast.com/basics/install-an-extension#web-store) * [Use installed extensions](https://developers.raycast.com/basics/install-an-extension#use-installed-extensions) --- # Review an Extension in a Pull Request | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/basics/review-pullrequest.md) . All updates to an extension are made through a [Pull Request](https://github.com/raycast/extensions/pulls) - if you need to review whether the Pull Request works as expected, then you can checkout the fork within a few seconds. [](https://developers.raycast.com/basics/review-pullrequest#steps) Steps ----------------------------------------------------------------------------- 1. Open a terminal window 2. Navigate to a folder where you want the repository to land 3. Run the below commands _There are a few things you'll need to find and insert manually in the snippet below_ **FORK\_URL** Open the PR and click on the incoming ref as shown below ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-1a66bb065c6f9ccb78f4a42eebdcd3c70837fb1d%252Fgo-to-ref.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=a36d64d8&sv=2) Now click the code button and copy the HTTPS path from the dropdown **BRANCH** You can see the branch on the above image (in this example it’s `notion-quicklinks`) **EXTENSION\_NAME** Click the `Files Changed` tab to see in which directory files have been changed (in this example it’s `notion`) 1. That's it, the extension should now be attached in Raycast [PreviousInstall an Extension](https://developers.raycast.com/basics/install-an-extension) [NextGetting Started](https://developers.raycast.com/ai/getting-started) Last updated 6 months ago Copy BRANCH="ext/soundboard" FORK_URL="https://github.com/pernielsentikaer/raycast-extensions.git" EXTENSION_NAME="soundboard" git clone -n --depth=1 --filter=tree:0 -b ${BRANCH} ${FORK_URL} cd raycast-extensions git sparse-checkout set --no-cone "extensions/${EXTENSION_NAME}" git checkout cd "extensions/${EXTENSION_NAME}" npm install && npm run dev --- # Prepare an Extension for Store | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/basics/prepare-an-extension-for-store.md) . Here you will find requirements and guidelines that you'll need to follow in order to get through the review before your extension becomes available in the Store. Please read it carefully because it will save time for you and for us. This document is constantly evolving so please do visit it from time to time. [](https://developers.raycast.com/basics/prepare-an-extension-for-store#metadata-and-configuration) Metadata and Configuration ----------------------------------------------------------------------------------------------------------------------------------- * Things to double-check in your `package.json` * Ensure you use your **Raycast** account username in the `author` field * Ensure you use `MIT` in the `license` field * Ensure you are using the latest Raycast API version * Ensure the `platforms` field matching the requirement of your extension, eg. if you use platform-specific APIs, restrict the `platforms` field to the corresponding platform * Please use `npm` for installing dependencies and include `package-lock.json` in your pull request. We use `npm` on our Continuous Integration (CI) environment when building and publishing extensions so, by providing a `package-lock.json` file, we ensure that the dependencies on the server match the same versions as your local dependencies. * Please check the terms of service of third-party services that your extension uses. * Read the [Extension Guidelines](https://manual.raycast.com/extensions-guidelines) and make sure that your Extension comply with it. * Make sure to **run a distribution build** with `npm run build` locally before submitting the extension for review. This will perform additional type checking and create an optimized build. Open the extension in Raycast to check whether everything works as expected with the distribution build. In addition, you can perform linting and code style checks by running `npm run lint`. (Those checks will later also run via automated GitHub checks.) [](https://developers.raycast.com/basics/prepare-an-extension-for-store#extensions-and-commands-naming) Extensions and Commands Naming ------------------------------------------------------------------------------------------------------------------------------------------- * Extension and command titles should follow [**Apple Style Guide**](https://help.apple.com/applestyleguide/#/apsgb744e4a3?sub=apdca93e113f1d64) convention * βœ… `Google Workplace`, `Doppler Share Secrets`, `Search in Database` * ❌ `Hacker news`, `my issues` * πŸ€” It's okay to use lower case for names and trademarks that are canonically written with lower case letters. E.g. `iOS` , `macOS` , `npm`. * **Extension title** * It will be used only in the Store and in the preferences * Make it easy for people to understand what it does when they see it in the Store * βœ… `Emoji Search`, `Airport - Discover Testflight Apps`, `Hacker News` * ❌ `Converter`, `Images`, `Code Review`, `Utils` * πŸ€” In some cases, you can add additional information to the title similar to the Airport example above. Only do so if it adds context. * πŸ’‘ You can use more creative titles to differentiate your extension from other extensions with similar names. * Aim to use nouns rather than verbs * `Emoji Search` is better than `Search Emoji` * Avoid generic names for an extension when your extension doesn't provide a lot of commands * E.g. if your extension can only search pages in Notion, name it `Notion Search` instead of just `Notion`. This will help users to form the right expectations about your extension. If your extension covers a lot of functionality, it's okay to use a generic name like `Notion`. Example: [GitLab](https://www.raycast.com/tonka3000/gitlab) . * **Rule of thumb:** If your extension has only one command, you probably need to name the extension close to what this command does. Example: [Visual Studio Code Recent Projects](https://www.raycast.com/thomas/visual-studio-code) instead of just `Visual Studio Code`. * **Extension description** * In one sentence, what does your extension do? This will be shown in the list of extensions in the Store. Keep it short and descriptive. See how other approved extensions in the Store do it for inspiration. * **Command title** * Usually it's ` ` structure or just `` * The best approach is to see how other commands are named in Raycast to get inspiration * βœ… `Search Recent Projects`, `Translate`, `Open Issues`, `Create Task` * ❌ `Recent Projects Search`, `Translation`, `New Task` * Avoid articles * βœ… `Search Emoji`, `Create Issue` * ❌ `Search an Emoji`, `Create an Issue` * Avoid just giving it a service name, be more specific about what the command does * βœ… `Search Packages` * ❌ `NPM` * **Command subtitle** * Use subtitles to add context to your command. Usually, it's an app or service name that you integrate with. It makes command names more lightweight and removes the need to specify a service name in the command title. * The subtitle is indexed so you can still search using subtitle and title: `xcode recent projects` would return `Search Recent Projects` in the example above. * Don't use subtitles as descriptions for your command * ❌ `Quickly open Xcode recent projects` * Don't use a subtitle if it doesn't add context. Usually, this is the case with single command extensions. * There is no need for a subtitle for the `Search Emoji` command since it's self-explanatory * **Rule of thumb:** If your subtitle is almost a duplication of your command title, you probably don't need it ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-d482752e8c76fe94fcdd4adf8d5b8ab0b94126d9%252Fgood-subtitle.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=1ee5cba4&sv=2) Example of a good subtitle [](https://developers.raycast.com/basics/prepare-an-extension-for-store#extension-icon) Extension Icon ----------------------------------------------------------------------------------------------------------- We made a new icon generator tool to ease the process of creating icons for your extensions. You can find it [here](https://icon.ray.so/) . * The published extension in the Store should have a 512x512px icon in `png` format * The icon should look good in both light and dark themes (you can switch the theme in Raycast Preferences β†’ Appearance) * If you have separate light and dark icons, refer to the `package.json` [manifest](https://developers.raycast.com/information/manifest#extension-properties) documentation on how to configure them * Extensions that use the default Raycast icon will be rejected * This [Icon Template](https://www.figma.com/community/file/1030764827259035122/Extensions-Icon-Template) can help you with making and exporting a proper icon * Make sure to remove unused assets and icons * πŸ’‘ If you feel like designing icons is not up to your alley, ask [community](https://raycast.com/community) for help (#extensions channel) [](https://developers.raycast.com/basics/prepare-an-extension-for-store#provide-readme-if-additional-configuration-required) Provide README if Additional Configuration Required ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * If your extension requires additional setup, such as getting an API access token, enabling some preferences in other applications, or has non-trivial use cases, please provide a README file at the root folder of your extension. When a README is provided, users will see the "About This Extension" button on the preferences onboarding screen. * Supporting README media: Put all linked media files in a top-level `media` folder inside your extension directory. (This is different from assets that are required at runtime in your extension: they go inside the assets folder and will be bundled into your extension.) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-8bc31854cf0c64fdff60dd1782a7cce0c6acb97b%252Frequired-preference.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=b537c0bf&sv=2) Onboarding button linking to the README file [](https://developers.raycast.com/basics/prepare-an-extension-for-store#categories) Categories --------------------------------------------------------------------------------------------------- ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-b96d3ca00c7089cee075510e1e4b13a60eddfe64%252Fcategories-focus.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=4e7fcb23&sv=2) Categories shown on an extension details screen * All extensions should be published with at least one category * Categories are case-sensitive and should follow the [Title Case](https://titlecaseconverter.com/rules/) convention * Add categories in the `package.json` [manifest](https://developers.raycast.com/information/manifest) file or select the categories when you create a new extension using the **Create Extension** command ### [](https://developers.raycast.com/basics/prepare-an-extension-for-store#all-categories) All Categories Category Example Applications [Cleanshot X](https://www.raycast.com/Aayush9029/cleanshotx) – Capture and record your screen Communication [Slack Status](https://www.raycast.com/petr/slack-status) – Quickly change your Slack status. Data [Random Data Generator](https://www.raycast.com/loris/random) – Generate random data using Faker library. Documentation [Tailwind CSS Documentation](https://www.raycast.com/vimtor/tailwindcss) – Quickly search Tailwind CSS documentation and open it in the browser. Design Tools [Figma File Search](https://www.raycast.com/michaelschultz/figma-files-raycast-extension) – Lists Figma files allowing you to search and navigate to them. Developer Tools [Brew](https://www.raycast.com/nhojb/brew) – Search and install Homebrew formulae. Finance [Coinbase Pro](https://www.raycast.com/farisaziz12/coinbase-pro) – View your Coinbase Pro portfolio. Fun [8 Ball](https://www.raycast.com/rocksack/8-ball) – Returns an 8 ball like answer to questions. Media [Unsplash](https://www.raycast.com/eggsy/unsplash) – Search images or collections on Unsplash, download, copy or set them as wallpaper without leaving Raycast. News [Hacker News](https://www.raycast.com/thomas/hacker-news) – Read the latest stories of Hacker News. Productivity [Todoist](https://www.raycast.com/thomaslombart/todoist) – Check your Todoist tasks and quickly create new ones. Security [1Password 7](https://www.raycast.com/khasbilegt/1password7) – Search, open or edit your 1Password 7 passwords from Raycast. System [Coffee](https://www.raycast.com/mooxl/coffee) – Prevent the sleep function on your mac. Web [Wikipedia](https://www.raycast.com/vimtor/wikipedia) – Search Wikipedia articles and view them. Other To be used if you think your extension doesn’t fit in any of the above categories. [](https://developers.raycast.com/basics/prepare-an-extension-for-store#screenshots) Screenshots ----------------------------------------------------------------------------------------------------- ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-fd3ba451deb85e08069572e61a3d138530f3e27a%252Fhn-store.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=8456c2e0&sv=2) An example of an extension with screenshot metadata * Screenshots are displayed in the metadata of an extension details screen, where users can click and browse through them to understand what your extension does in greater detail, before installing * You can add a maximum of six screenshots. We recommend adding at least three, so your extensions detail screen looks beautiful. ### [](https://developers.raycast.com/basics/prepare-an-extension-for-store#adding-screenshots) Adding Screenshots In Raycast 1.37.0+ we made it easy for you to take beautiful pixel perfect screenshots of your extension with an ease. #### [](https://developers.raycast.com/basics/prepare-an-extension-for-store#how-to-use-it) How to use it? Raycast v1 Raycast v2 1. Set up Window Capture in Advanced Preferences (Hotkey e.g.: `βŒ˜β‡§βŒ₯+M`) 2. Ensure your extension is opened in development mode (Window Capture eliminates dev-related menus/icons). 3. Open the command 4. Press the hotkey, remember to tick `Save to Metadata` 1. Set a hotkey for the command `Capture Window` 2. Open the command you want to take a screenshot of and run your hotkey 3. Remember to tick the `Save to Metadata` checkbox and click the camera button 4. Continue for all the commands you want screenshots of This only works if you have a `metadata` folder in your extension; if not, create it manually before doing the steps above. This tool will use your current background. Choose a background image with a good contrast that makes it clear and easy to see the app and extension you've made. You can use [Raycast Wallpapers](https://www.raycast.com/wallpapers) to make your background look pretty ### [](https://developers.raycast.com/basics/prepare-an-extension-for-store#specifications) Specifications Screenshot size Aspect ratio Format Dark mode support 2000 x 1250 pixels (landscape) 16:10 PNG No ### [](https://developers.raycast.com/basics/prepare-an-extension-for-store#dos-and-donts) Do's & Dont's * βœ… Choose a background with good contrast, that makes it clear and easy to see the app and extension you’ve made * βœ… Select the most informative commands to showcase what your extension does – focus on giving the user as much detail as possible * ❌ Do not use multiple backgrounds for different screenshots – be consistent and use the same across all screenshots * ❌ Do not share sensitive data in your screenshots – these will be visible in the Store, as well as the Extension repository on GitHub * ❌ Do not include screenshots of other applications - keep the focus entirely on your extension within Raycast * ❌ Avoid using screenshots in different themes (light and dark), unless it is to demonstrate what your extension does [](https://developers.raycast.com/basics/prepare-an-extension-for-store#version-history) Version History ------------------------------------------------------------------------------------------------------------- ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-4e39429865f934bd7684631765f8cbfa902750f9%252Fversion-history.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=4685b5a3&sv=2) A CHANGELOG.md file displayed in the app * Make it easier for users to see exactly what notable changes have been made between each release of your extension with a `CHANGELOG.md` file in your extension metadata * To add Version History to your extension, add a `CHANGELOG.md` file to the root folder of your extension * See an extension files structure with [screenshots and a changelog file](https://developers.raycast.com/basics/prepare-an-extension-for-store#adding-screenshots) * With each modification, provide clear and descriptive details regarding the latest update, accompanied by a title formatted as an h2 header followed by `{PR_MERGE_DATE}`. This placeholder will be automatically replaced when the pull request is merged. While you may still use the date timestamp format YYYY-MM-DD, it is often more practical to use `{PR_MERGE_DATE}` since merging of a pull request can take several days (depending on the review comments, etc.). * Make sure your change title is within square brackets * Separate your title and date with a hyphen `-` and spaces either side of the hyphen * Below is an example of a changelog that follows the correct format ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2Fuser-images.githubusercontent.com%2F17166544%2F159987128-1e9f22a6-506b-4edd-bb40-e121bfdc46f8.png&width=768&dpr=3&quality=100&sign=ede11e85&sv=2) An extensions version history on raycast.com/store You can use [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) to help you format your changelog correctly [](https://developers.raycast.com/basics/prepare-an-extension-for-store#contributing-to-existing-extensions-vs-creating-a-new-one) Contributing to Existing Extensions vs Creating a New One ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * **When you should contribute to an existing extension instead of creating a new one** * You want to make a small improvement to an extension that is already published, e.g. extra actions, new preference, UX improvements, etc.. Usually, it's a non-significant change. * You want to add a simple command that compliments an existing extension without changing the extension title or description, e.g. you want to add "Like Current Track" command for Spotify. It wouldn't make sense to create a whole new extension just for this when there is already the [Spotify Controls](https://www.raycast.com/thomas/spotify-controls) extension. * **Important:** If your change is significant, it makes sense to contact the author of the extension before you invest a lot of time into it. We cannot merge significant contributions without the author's sign-off. * **When you should consider creating a new extension instead of contributing to an existing one** * The changes to an existing extension would be significant and might break other people's workflows. Check with the author if you want to proceed with the collaboration path. * Your extension provides an integration with the same service but has a different configuration, e.g. one extension could be "GitHub Cloud", another "GitHub Enterprise". One extension could be "Spotify Controls" and only uses AppleScript to play/pause songs, while another extension can provide deeper integration via the API and require an access token setup. There is no reason to try to merge everything together as this would only make things more complicated. * **Multiple simple extensions vs one large one** * If your extension works standalone and brings something new to the Store, it's acceptable to create a new one instead of adding commands to an existing one. E.g. one extension could be "GitHub Repository Search", another one could be "GitHub Issue Search". It should not be the goal to merge all extensions connecting with one service into one mega extension. However, it's also acceptable to merge two extensions under one if the authors decide to do so. [](https://developers.raycast.com/basics/prepare-an-extension-for-store#binary-dependencies-and-additional-configuration) Binary Dependencies and Additional Configuration ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- * Avoid asking users to perform additional downloads and try to automate as much as possible from the extension, especially if you are targeting non-developers. See the [Speedtest](https://github.com/raycast/extensions/pull/302) extension that downloads a CLI in the background and later uses it under the hood. * If you do end up downloading executable binaries in the background, please make sure it's done from a server that you don't have access to. Otherwise, we cannot guarantee that you won't replace the binary with malicious code after the review. E.g. downloading `speedtest-cli` from [`install.speedtest.net`](http://install.speedtest.net/) is acceptable, but doing this from some custom AWS server would lead to a rejection. Add additional integrity checks through hashes. * Don't bundle opaque binaries where sources are unavailable or where it's unclear how they have been built. * Don't bundle heavy binary dependencies in the extension – this would lead to an increased extension download size. * **Examples for interacting with binaries** * βœ… Calling known system binaries * βœ… Binary downloaded or installed from a trusted location with additional integrity checking through hashes (that is, verify whether the downloaded binary really matches the expected binary) * βœ… Binary extracted from an npm package and copied to assets, with traceable sources how the binary is built; **note**: we have yet to integrate CI actions for copying and comparing the files; meanwhile, ask a member of the Raycast team to add the binary for you * ❌ Any binary with unavailable sources or unclear builds just added to the assets folder [](https://developers.raycast.com/basics/prepare-an-extension-for-store#keychain-access) Keychain Access ------------------------------------------------------------------------------------------------------------- * Extensions requesting Keychain Access will be rejected due to security concerns. If you can't work around this limitation, reach out to us on [Slack](https://raycast.com/community) or via `feedback@raycast.com`. [](https://developers.raycast.com/basics/prepare-an-extension-for-store#ui-ux-guidelines) UI/UX Guidelines --------------------------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/basics/prepare-an-extension-for-store#preferences) Preferences ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-a1ab8634fce260f92c072f77830f843cbd2a55a2%252Frequired-preferences-2.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=d7643985&sv=2) Required preferences will be shown when opening the command * Use the [preferences API](https://developers.raycast.com/api-reference/preferences) to let your users configure your extension or for providing credentials like API tokens * When using `required: true`, Raycast will ask the user to set preferences before continuing with an extension. See the example [here](https://github.com/raycast/extensions/blob/main/extensions/gitlab/package.json#L150) . * You should not build separate commands for configuring your extension. If you miss some API to achieve the preferences setup you want, please file a [GitHub issue](https://github.com/raycast/extensions/issues) with a feature request. ### [](https://developers.raycast.com/basics/prepare-an-extension-for-store#action-panel) Action Panel ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-25a03b5271959426230e724a733f30e7597dd1bf%252Faction-panel.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=fed1aeb0&sv=2) Raycast Action Panel component * Actions in the action panel should also follow the **Title Case** naming convention * βœ… `Open in Browser`, `Copy to Clipboard` * ❌ `Copy url`, `set project`, `Set priority` * Provide icons for actions if there are other actions with icons in the list * Avoid having a list of actions where some have icons and some don't * Add ellipses `…` for actions that will have a submenu. Don't repeat the parent action name in the submenu * βœ… `Set Priority…` and submenu would have `Low`, `Medium`, `High` * ❌ `Set Priority` and submenu would have `Set Priority Low`, `Set Priority Medium`, etc ### [](https://developers.raycast.com/basics/prepare-an-extension-for-store#navigation) Navigation * Use the [Navigation API](https://developers.raycast.com/api-reference/user-interface/navigation) for pushing new screens. This will ensure that a user can navigate within your extension the same way as in the rest of the application. * Avoid introducing your own navigation stack. Extensions that just replace the view's content when it's expected to push a new screen will be rejected. ### [](https://developers.raycast.com/basics/prepare-an-extension-for-store#empty-states) Empty States * When you update lists with an empty array of elements, the "No results" view will be shown. You can customize this view by using the [List.EmptyView](https://developers.raycast.com/api-reference/user-interface/list#list.emptyview) or [Grid.EmptyView](https://developers.raycast.com/api-reference/user-interface/grid#grid.emptyview) components. * **Common mistake** - "flickering empty state view" on start * If you try rendering an empty list before real data arrives (e.g. from the network or disk), you might see a flickering "No results" view when opening the extension. To prevent this, make sure not to return an empty list of items before you get the data you want to display. In the meantime, you can show the loading indicator. See [this example](https://developers.raycast.com/information/best-practices#show-loading-indicator) . ### [](https://developers.raycast.com/basics/prepare-an-extension-for-store#navigation-title) Navigation Title * Don't change the `navigationTitle` in the root command - it will be automatically set to the command name. Use `navigationTitle` only in nested screens to provide additional context. See [Slack Status extension](https://github.com/raycast/extensions/blob/020f2232aa5579b5c63b4b3c08d23ad719bce1f8/extensions/slack-status/src/setStatusForm.tsx#L95) as an example of correct usage of the `navigationTitle` property. * Avoid long titles. If you can't predict how long the navigation title string will be, consider using something else. E.g. in the Jira extension, we use the issue key instead of the issue title to keep it short. * Avoid updating the navigation title multiple times on one screen depending on some state. If you find yourself doing it, there is a high chance you are misusing it. ### [](https://developers.raycast.com/basics/prepare-an-extension-for-store#placeholders-in-text-fields) Placeholders in Text Fields * For a better visual experience, add placeholders in text field and text area components. This includes preferences. * Don't leave the search bar without a placeholder ### [](https://developers.raycast.com/basics/prepare-an-extension-for-store#analytics) Analytics * It’s not allowed to include external analytics in extensions. Later on, we will add support to give developers more insights into how their extension is being used. ### [](https://developers.raycast.com/basics/prepare-an-extension-for-store#localization-language) Localization / Language * At the moment, Raycast doesn't support localization and only supports US English. Therefore, please avoid introducing your custom way to localize your extension. If the locale might affect functionality (e.g. using the correct unit of measurement), please use the preferences API. * Use US English spelling (not British) [PreviousContribute to an Extension](https://developers.raycast.com/basics/contribute-to-an-extension) [NextPublish an Extension](https://developers.raycast.com/basics/publish-an-extension) Last updated 7 days ago * [Metadata and Configuration](https://developers.raycast.com/basics/prepare-an-extension-for-store#metadata-and-configuration) * [Extensions and Commands Naming](https://developers.raycast.com/basics/prepare-an-extension-for-store#extensions-and-commands-naming) * [Extension Icon](https://developers.raycast.com/basics/prepare-an-extension-for-store#extension-icon) * [Provide README if Additional Configuration Required](https://developers.raycast.com/basics/prepare-an-extension-for-store#provide-readme-if-additional-configuration-required) * [Categories](https://developers.raycast.com/basics/prepare-an-extension-for-store#categories) * [All Categories](https://developers.raycast.com/basics/prepare-an-extension-for-store#all-categories) * [Screenshots](https://developers.raycast.com/basics/prepare-an-extension-for-store#screenshots) * [Adding Screenshots](https://developers.raycast.com/basics/prepare-an-extension-for-store#adding-screenshots) * [Specifications](https://developers.raycast.com/basics/prepare-an-extension-for-store#specifications) * [Do's & Dont's](https://developers.raycast.com/basics/prepare-an-extension-for-store#dos-and-donts) * [Version History](https://developers.raycast.com/basics/prepare-an-extension-for-store#version-history) * [Contributing to Existing Extensions vs Creating a New One](https://developers.raycast.com/basics/prepare-an-extension-for-store#contributing-to-existing-extensions-vs-creating-a-new-one) * [Binary Dependencies and Additional Configuration](https://developers.raycast.com/basics/prepare-an-extension-for-store#binary-dependencies-and-additional-configuration) * [Keychain Access](https://developers.raycast.com/basics/prepare-an-extension-for-store#keychain-access) * [UI/UX Guidelines](https://developers.raycast.com/basics/prepare-an-extension-for-store#ui-ux-guidelines) * [Preferences](https://developers.raycast.com/basics/prepare-an-extension-for-store#preferences) * [Action Panel](https://developers.raycast.com/basics/prepare-an-extension-for-store#action-panel) * [Navigation](https://developers.raycast.com/basics/prepare-an-extension-for-store#navigation) * [Empty States](https://developers.raycast.com/basics/prepare-an-extension-for-store#empty-states) * [Navigation Title](https://developers.raycast.com/basics/prepare-an-extension-for-store#navigation-title) * [Placeholders in Text Fields](https://developers.raycast.com/basics/prepare-an-extension-for-store#placeholders-in-text-fields) * [Analytics](https://developers.raycast.com/basics/prepare-an-extension-for-store#analytics) * [Localization / Language](https://developers.raycast.com/basics/prepare-an-extension-for-store#localization-language) Copy # Brew Changelog ## [Added a bunch of new feedback] - {PR_MERGE_DATE} - Improve reliability of `outdated` command - Add action to copy formula/cask name - Add cask name & tap to cask details - Add Toast action to cancel current action - Add Toast action to copy error log after failure ## [New Additions] - 2022-12-13 - Add greedy upgrade preference - Add `upgrade` command ## [Fixes & Bits] - 2021-11-19 - Improve discovery of brew prefix - Update Cask.installed correctly after installation - Fix installed state after uninstalling search result - Fix cache check after installing/uninstalling cask - Add uninstall action to outdated action panel ## [New Commands] - 2021-11-04 Add support for searching and managing casks ## [Added Brew] - 2021-10-26 Initial version code --- # Create an AI Extension | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/ai/create-an-ai-extension.md) . To turn your regular extension into an AI-powered one, you need to add a set of tools that allow Raycast AI to interact with your extension. [](https://developers.raycast.com/ai/create-an-ai-extension#add-ai-tools) Add AI Tools ------------------------------------------------------------------------------------------- The simplest way to add a tool to your extensions is to open the Manage Extensions command, search for your extension and perform the Add New Tool action via the Action Panel (or press `βŒ₯` `⌘` `T`). ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-1be2e53c0b44ea6d5b7b3071c72b9747c88ea1f1%252Fadd-new-tool.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=58e59f5e&sv=2) Add New Tool Alternatively you can edit the [`package.json` file](https://developers.raycast.com/information/manifest) manually and add a new entry to the `tools` array. Give the tool a name, a description, and pick a template. The name and description will show up in the UI as well as the Store. The description is passed to AI to help it understand how to use the tool. [](https://developers.raycast.com/ai/create-an-ai-extension#build-your-ai-extension) Build Your AI Extension ----------------------------------------------------------------------------------------------------------------- Just like with regular extensions, you need to build your AI Extension. After you've added a tool, switch to your terminal and navigate to your extension directory. Run `npm install && npm run dev` to start the extension in development mode. `npm run dev` starts the extension in development mode with hot reloading, error reporting and [more](https://developers.raycast.com/information/developer-tools/cli#development) . [](https://developers.raycast.com/ai/create-an-ai-extension#use-your-ai-extension) Use Your AI Extension ------------------------------------------------------------------------------------------------------------- Open Raycast, and you'll notice a new list item saying "Ask ..." at the top of the root search. Press `↡` to open it. From there on, you can chat to your AI Extension. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-23cf3dba982add079b5ee80f7cad37b49dee0e13%252Fuse-ai-extension.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=25793fc6&sv=2) AI Extension Alternatively, you can open Raycast's AI Chat and start chatting to your AI Extension there. Simply type `@` and start typing the name of your extension. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-c8184957f84dd38b6ec5234940c1266a9d7519f9%252Fai-chat.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=280f7b8d&sv=2) AI Chat πŸŽ‰ Congratulations! You built your first AI extension. Now you can start adding more tools to your extension to make it more powerful. [PreviousGetting Started](https://developers.raycast.com/ai/getting-started) [NextLearn Core Concepts of AI Extensions](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions) Last updated 1 year ago * [Add AI Tools](https://developers.raycast.com/ai/create-an-ai-extension#add-ai-tools) * [Build Your AI Extension](https://developers.raycast.com/ai/create-an-ai-extension#build-your-ai-extension) * [Use Your AI Extension](https://developers.raycast.com/ai/create-an-ai-extension#use-your-ai-extension) --- # Getting Started | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/ai/getting-started.md) . There are two ways to leverage the power of AI inside your extensions. To use AI APIs or AI Extensions, you need to subscribe to [Raycast Pro](https://raycast.com/pro) . [](https://developers.raycast.com/ai/getting-started#ai-apis) AI APIs -------------------------------------------------------------------------- Use our [AI APIs](https://developers.raycast.com/api-reference/ai) to generate content such as summaries, translations, and more. For example, the [Notion extension](https://raycast.com/notion/notion) uses `AI.ask(...)` as part of its Quick Capture command to generate a summary of a website. [](https://developers.raycast.com/ai/getting-started#ai-extensions) AI Extensions -------------------------------------------------------------------------------------- Create an [AI Extension](https://developers.raycast.com/ai/create-an-ai-extension) to enable natural language interactions in Quick AI, AI Chat, and AI Commands. For example, the [Linear extension](https://www.raycast.com/linear/linear) allows you to manage your team's issues or check your personal priorities by simply chatting to it. [PreviousReview an Extension in a Pull Request](https://developers.raycast.com/basics/review-pullrequest) [NextCreate an AI Extension](https://developers.raycast.com/ai/create-an-ai-extension) Last updated 6 days ago * [AI APIs](https://developers.raycast.com/ai/getting-started#ai-apis) * [AI Extensions](https://developers.raycast.com/ai/getting-started#ai-extensions) --- # Learn Core Concepts of AI Extensions | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions.md) . AI Extensions rely on three core concepts: Tools, Instructions, and Evals. Each of these concepts plays a crucial role in the development of AI Extensions. Let's take a closer look at each of them. [](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#tools) Tools ------------------------------------------------------------------------------------------- To turn a regular extension into an AI extension, you need to add a set of tools that allow Raycast AI to interact with your extension. A tool is a function that takes an input and returns a value. Here's an example of a simple tool: Copy export default function tool() { return "Hello, world!"; } ### [](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#inputs) Inputs Tools can take an input. For example, a `greet` tool takes a `name` as an input and returns a greeting to the user. Copy type Input = { name: string; }; export default function tool(input: Input) { return `Hello, ${input.name}!`; } Those inputs can be used to provide more context to the tool. For example, you can pass a title, a description, and a due date to a `createTask` tool. A tool expects a single object as its input. ### [](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#descriptions) Descriptions To better teach AI how to use your tools, you can add descriptions as JSDoc comments (eg. `/** ... */`) to tools and their inputs. The better you describe your tools, the more likely AI is to use them correctly. ### [](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#confirmations) Confirmations Sometimes you want to keep the human in the loop. For example, you can ask the user to confirm an action before it is executed. For this, you can export a `confirmation` function. The `confirmation` function is called before the actual tool is executed. If the user confirms, the tool is executed afterwards. If the user cancels, the tool is not executed. You can customize the confirmation further by providing details about the action that needs to be confirmed. See [Tool Reference](https://developers.raycast.com/api-reference/tool) for more information. [](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#instructions) Instructions --------------------------------------------------------------------------------------------------------- Sometimes you want to provide additional instructions to the AI that are not specific to a single tool but to the entire AI extension. For example, you can provide a list of do's and don'ts for the AI to follow. Those are defined in the [`package.json` file](https://developers.raycast.com/information/manifest) under the `ai` key. A user can use multiple AI Extensions in a conversation. Therefore, you should make sure that your instructions don't conflict with the instructions of other AI Extensions. For example, avoid phrases like "You are a ... assistant" because other AI Extensions might provide a different skill set. Instead, you should focus on providing general instructions that describe the specifics of your AI Extension. For example, describe the relationship between issues, projects, and teams for a project management app. [](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#evals) Evals ------------------------------------------------------------------------------------------- Evals are a way to test your AI extension. Think of them as integrations tests. They are defined in the [`package.json` file](https://developers.raycast.com/information/manifest) under the `ai` key. They are also used as suggested prompts for the user to learn how to make the most out of your AI Extension. [](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#structure) Structure --------------------------------------------------------------------------------------------------- An eval consists of the following parts: * `input` is a text prompt that you expect from users of your AI Extension. It should include `@` mention the name of your extension (`name` from `package.json`). * `mocks` – mocked results of tool calls. It is required to give AI the context, i.e. if you write an eval for `@todo-list What are my todos?` you need to provide the actual list in `get-todos` mock. * `expected` – array of expectations, similar to `expect` statements in unit / integration tests. * `usedAsExample` – if true, the eval will be used as an example prompt for the user. True by default. [](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#expectations) Expectations --------------------------------------------------------------------------------------------------------- Expectations are used to check if the AI response matches the expected behavior. You have different options to choose from: * `includes`: Check that AI response includes some substring (case-insensitive), for example `{"includes": "added" }` * `matches`: Check that AI response matches some regexp, for example check if response contains a Markdown link `{ "matches": "\\[([^\\]]+)\\]\\(([^\\s\\)]+)(?:\\s+\"([^\"]+)\")?\\)" }` * `meetsCriteria`: Check that AI response meets some plain-text criteria (validated using AI). Useful when AI varies the response and it is hard to match it using `includes` or `matches`. Example: `{ "meetsCriteria": "Tells that label with this name doesn't exist" }` * `callsTool`: Check that during the request AI called some tool included from your AI extension. There are two forms: * Short form to check if AI tool with specific name was called. Example: `{ "callsTool": "get-todos" }` * Long form to check tool arguments: `{ callsTool: { name: "name", arguments: { arg1: matcher, arg2: matcher } } }`. Matches could be complex and combine any supported rules: * `eq` (used by default for any value that is not object or array) * `includes` * `matches` * `and` (used by default if array is used) * `or` * `not` #### [](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#example) Example Simple Expectation Nested Expectations Nested Expectations With Dot Notation Negative Expectation [](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#ai-file) AI File ----------------------------------------------------------------------------------------------- Your instructions or evals can start to become rather long and clutter your `package.json` file, for this reason, we recommend you to use a `ai.yaml` file in the root of your extension next to the `package.json` file. ai.yaml [PreviousCreate an AI Extension](https://developers.raycast.com/ai/create-an-ai-extension) [NextWrite Evals for Your AI Extension](https://developers.raycast.com/ai/write-evals-for-your-ai-extension) Last updated 3 months ago * [Tools](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#tools) * [Inputs](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#inputs) * [Descriptions](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#descriptions) * [Confirmations](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#confirmations) * [Instructions](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#instructions) * [Evals](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#evals) * [Structure](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#structure) * [Expectations](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#expectations) * [AI File](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#ai-file) Copy type Input = { /** * The title of the task */ title: string; /** * The description of the task */ description?: string; /** * The due date of the task in ISO 8601 format */ dueDate?: string; }; export default function tool(input: Input) { // ... create the task } Copy type Input = { /** * The first name of the user to greet */ name: string; }; /** * Greet the user with a friendly message */ export default function tool(input: Input) { return `Hello, ${input.name}!`; } Copy import { Tool } from "@raycast/api"; type Input = { /** * The first name of the user to greet */ name: string; }; export const confirmation: Tool.Confirmation = async (input) => { return { message: `Are you sure you want to greet ${input.name}?`, }; }; /** * Greet the user with a friendly message */ export default function tool(input: Input) { return `Hello, ${input.name}!`; } Copy { "ai": { "instructions": "When you don't know the user's first name, ask for it." } } Copy { "ai": { "evals": [\ {\ "expected": [\ {\ "callsTool": {\ "name": "greet",\ "arguments": {\ "name": "thomas"\ }\ }\ }\ ]\ }\ ] } } Copy { "ai": { "evals": [\ {\ "expected": [\ {\ "callsTool": {\ "name": "create-comment",\ "arguments": {\ "issueId": "ISS-1",\ "body": {\ "includes": "waiting for design"\ }\ }\ }\ }\ ]\ }\ ] } } Copy { "ai": { "evals": [\ {\ "expected": [\ {\ "callsTool": {\ "name": "greet",\ "arguments": {\ "user.name": "thomas"\ }\ }\ }\ ]\ }\ ] } } Copy { "ai": { "evals": [\ {\ "expected": [\ {\ "not": {\ "callsTool": "create-issue"\ }\ }\ ]\ }\ ] } } Copy instructions: | When you don't know the user's first name, ask for it. --- # Follow Best Practices for AI Extensions | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/ai/follow-best-practices-for-ai-extensions.md) . Working with LLMs can be tricky. Here are some best practices to make the most out of your AI Extension. 1. Use [Confirmations](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#confirmations) to keep the human in the loop. You can use them dynamically based on the user's input. For example, you might ask for confirmation if moving a file would overwrite an existing file but not if it would create a new file. 2. Write [Evals](https://developers.raycast.com/ai/write-evals-for-your-ai-extension) for common use-cases to test your AI Extension and provide users with suggested prompts. 3. Include information in your tool's input on how to format parameters like IDs or dates. For example, you might mention that a date should be provided in ISO 8601 format. 4. Include information in your tool's input on how to get the required parameters. For example, you want to teach AI how to get a team ID that is required to create a new issue. [PreviousWrite Evals for Your AI Extension](https://developers.raycast.com/ai/write-evals-for-your-ai-extension) [NextGetting Started](https://developers.raycast.com/teams/getting-started) Last updated 1 year ago --- # Write Evals for Your AI Extension | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/ai/write-evals-for-your-ai-extension.md) . We all know that AI is not always reliable. This is why it's important to write evals for your AI Extension. Evals allow you to test your AI Extension and make sure it behaves as expected. [](https://developers.raycast.com/ai/write-evals-for-your-ai-extension#add-an-eval) Add an Eval ---------------------------------------------------------------------------------------------------- The easiest way to add an eval is to first use your AI Extension. Then, once Raycast AI used your tools to finish its response, you can use the Copy Eval action to copy the eval to your clipboard. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-b91e1651293f819adc528349025ebe722373f66e%252Fcopy-eval.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=5c784da9&sv=2) Copy Eval You can then paste the eval into the `evals` array in the [`package.json` file](https://developers.raycast.com/information/manifest) . [](https://developers.raycast.com/ai/write-evals-for-your-ai-extension#run-your-evals) Run Your Evals ---------------------------------------------------------------------------------------------------------- To run your evals, you can use the `npx ray evals` command. This will run the evals and print the results to the console. You get an overview of the evals that failed and the ones that passed. From here you can start improving the names and descriptions of your tools. Visit [Learn Core Concepts of AI Extensions](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions#evals) to learn more about the different types of evals you can write. [PreviousLearn Core Concepts of AI Extensions](https://developers.raycast.com/ai/learn-core-concepts-of-ai-extensions) [NextFollow Best Practices for AI Extensions](https://developers.raycast.com/ai/follow-best-practices-for-ai-extensions) Last updated 1 year ago * [Add an Eval](https://developers.raycast.com/ai/write-evals-for-your-ai-extension#add-an-eval) * [Run Your Evals](https://developers.raycast.com/ai/write-evals-for-your-ai-extension#run-your-evals) Copy { "ai": { "evals": [\ {\ "input": "@todo-list what are my open todos",\ "mocks": {\ "get-todos": [\ {\ "id": "Z5lF8F-lSvGCD6e3uZwkL",\ "isCompleted": false,\ "title": "Buy oat milk"\ },\ {\ "id": "69Ag2mfaDakC3IP8XxpXU",\ "isCompleted": false,\ "title": "Play with my cat"\ }\ ]\ },\ "expected": [\ {\ "callsTool": "get-todos"\ }\ ]\ }\ ] } } --- # Publish a Private Extension | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/teams/publish-a-private-extension.md) . To publish an extension, run `npm run publish` in the extension directory. The command verifies, builds and publishes the extension to the owner's store. The extension is only available to members of this organization. A link to your extension is copied to your clipboard to share it with your teammates. Happy publishing πŸ₯³ To mark an extension as private, you need to set the `owner` field in your `package.json` to your organization handle. If you don't know your handle, open the Manage Organization command, select your organization in the dropdown on the top right and perform the Copy Organization Handle action (`⌘` `⇧` `.`). Use the Create Extension command to create a private extension for your organization. To be able to publish a private extension to an organization, you need to be logged in. Raycast takes care of logging you in with the CLI as well. In case you aren't logged in or need to switch an account, you can run `npx ray login` and `npx ray logout`. [PreviousGetting Started](https://developers.raycast.com/teams/getting-started) [NextCollaborate on Private Extensions](https://developers.raycast.com/teams/collaborate-on-private-extensions) Last updated 4 years ago --- # Collaborate on Private Extensions | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/teams/collaborate-on-private-extensions.md) . Isn't it more fun to work with your colleagues together on your extension? For this, we recommend to share all your extensions in a single repository, similar to how we organize the [public store](https://raycast.com/store) . If you follow the [Getting Started guide](https://developers.raycast.com/teams/getting-started) , we will set up a local repository for you that is optimized for collaboration. As next steps, create a [new repository](https://github.com/new) and push the existing local repository. Afterwards, your teammates can check out the code and help you improve your extensions and add new ones. [PreviousPublish a Private Extension](https://developers.raycast.com/teams/publish-a-private-extension) [NextDoppler Share Secrets](https://developers.raycast.com/examples/doppler) Last updated 4 years ago --- # Getting Started | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/teams/getting-started.md) . Raycast for Teams allows you to build, share and discover extensions in a private store. The store is only accessible to members of your organization. [](https://developers.raycast.com/teams/getting-started#create-your-organization) Create Your Organization --------------------------------------------------------------------------------------------------------------- To get started, create your organization. Specify the name of the organization, a handle (used in links, e.g. `https://raycast.com/your_org/some_extension`) and optionally upload an avatar. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-3317f218fb9427f3c92c90475980f2859ea23e29%252Fteams-create-organization.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=c700d7b&sv=2) Create an Organization You can use the Manage Organization command to edit your organization's information later. [](https://developers.raycast.com/teams/getting-started#create-your-private-extension-store) Create Your Private Extension Store ------------------------------------------------------------------------------------------------------------------------------------- After you've created your organization, it's time to set up a private store for your extensions. ### [](https://developers.raycast.com/teams/getting-started#init-a-local-repository) Init a Local Repository First, select a folder to create a local repository for your private extension store. We create a folder that contains a Getting Started extension. We recommend to store all extensions of your team in a single repository. This makes it easy to collaborate. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-d151ce8f86dd834e2f26037740dc7892eb6d7b86%252Fteams-create-repository.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=856b536b&sv=2) Create Local Repository ### [](https://developers.raycast.com/teams/getting-started#build-the-getting-started-extension) Build The Getting Started Extension After you have created the local repository, navigate into the `getting-started` folder. The folder contains a simple extension with a command that shows a list with a few useful links. Run `npm run dev` in the folder to build the extension and start development mode. Raycast opens and you can see a new Development section in the root search. The section shows all commands that are under active development. You can open the command and open a few links. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-2460a8a8514ae682c51d68a7afb4d49bba089601%252Fteams-develop-extension.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=c0d41778&sv=2) Build the Getting Started Extension See [Create Your First Extension](https://developers.raycast.com/basics/create-your-first-extension) for a more detailed guide on how to create an extension. ### [](https://developers.raycast.com/teams/getting-started#publish-the-getting-started-extension) Publish The Getting Started Extension Now, we share the extension with your organization. Perform `npm run publish` in the extension folder. The command verifies, builds and publishes the extension to your private extension store. The extension is only accessible to members of your organization. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-3df843560081baea304cfb72cda40bc650398f06%252Fteams-publish-extension.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=b1032572&sv=2) Publish the Getting Started Extension πŸŽ‰ Congratulations! You built and published your first private extension. Now it's time to spread the word in your organization. [](https://developers.raycast.com/teams/getting-started#invite-your-teammates) Invite Your Teammates --------------------------------------------------------------------------------------------------------- Use the Copy Organization Invite Link command in Raycast to share access to your organization. Send the link to your teammates. You'll receive an email when somebody joins your organization. You can use the Manage Organization command to see who's part of your organization, reset the invite link and edit your organization details. As a next step, follow [this guide](https://developers.raycast.com/teams/collaborate-on-private-extensions) to push your local repository to a source control system. This allows you to collaborate with your teammates on your extensions. [PreviousFollow Best Practices for AI Extensions](https://developers.raycast.com/ai/follow-best-practices-for-ai-extensions) [NextPublish a Private Extension](https://developers.raycast.com/teams/publish-a-private-extension) Last updated 1 year ago * [Create Your Organization](https://developers.raycast.com/teams/getting-started#create-your-organization) * [Create Your Private Extension Store](https://developers.raycast.com/teams/getting-started#create-your-private-extension-store) * [Init a Local Repository](https://developers.raycast.com/teams/getting-started#init-a-local-repository) * [Build The Getting Started Extension](https://developers.raycast.com/teams/getting-started#build-the-getting-started-extension) * [Publish The Getting Started Extension](https://developers.raycast.com/teams/getting-started#publish-the-getting-started-extension) * [Invite Your Teammates](https://developers.raycast.com/teams/getting-started#invite-your-teammates) --- # File Structure | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/file-structure.md) . An extension consists of at least an entry point file (e.g. `src/index.ts`) and a `package.json` manifest file. We add a few more support files when scaffolding an extension to streamline development with modern JavaScript tooling. The typical directory structure of a newly created extension looks like this: Copy extension β”œβ”€β”€ .prettierrc β”œβ”€β”€ assets β”‚ └── icon.png β”œβ”€β”€ eslint.config.js β”œβ”€β”€ node_modules β”œβ”€β”€ package-lock.json β”œβ”€β”€ package.json β”œβ”€β”€ src β”‚ β”œβ”€β”€ command.tsx └── tsconfig.json The directory contains all source files, assets, and a few support files. Let's go over each of them: [](https://developers.raycast.com/information/file-structure#sources) Sources ---------------------------------------------------------------------------------- Put all your source files into the `src` folder. We recommend using TypeScript as a programming language. Our API is fully typed, which helps you catch errors at compile time rather than runtime. `ts`, `tsx`, `js` and `jsx` are supported as file extensions. As a rule of thumb, use `tsx` or `jsx` for commands with a UI. An extension consists of at least an entry point file (e.g. `src/command.ts`) per command and a `package.json` manifest file holding metadata about the extension, its commands, and its tools. The format of the manifest file is very similar to [that of npm packages](https://docs.npmjs.com/cli/v7/configuring-npm/package-json) . In addition to some of the standard properties, there are some [additional properties](https://developers.raycast.com/information/manifest) , in particular, the `commands` properties which describes the entry points exposed by the extension. Each command has a property `name` that maps to its main entry point file in the `src` folder. For example, a command with the name `create` in the `package.json` file, maps to the file `src/create{.ts,.tsx,.js,.jsx}`. [](https://developers.raycast.com/information/file-structure#assets) Assets -------------------------------------------------------------------------------- The optional `assets` folder can contain icons that will be packaged into the extension archive. All bundled assets can be referenced at runtime. Additionally, icons can be used in the `package.json` as extension or command icons. [](https://developers.raycast.com/information/file-structure#support-files) Support files ---------------------------------------------------------------------------------------------- The directory contains a few more files that setup common JavaScript tooling: * **eslint.config.js** describes rules for [ESLint](https://eslint.org/) , which you can run with `npm run lint`. It has recommendations for code style and best practices. Usually, you don't have to edit this file. * **.prettierrc** contains default rules for [Prettier](https://prettier.io/) to format your code. We recommend to setup the [VS Code extension](https://prettier.io/docs/en/editors.html#visual-studio-code) to keep your code pretty automatically. * **node\_modules** contains all installed dependencies. You shouldn't make any manual changes to this folder. * **package-lock.json** is a file generated by npm to install your dependencies. You shouldn't make any manual changes to this file. * **package.json** is the [manifest file](https://developers.raycast.com/information/manifest) containing metadata about your extension such as its title, the commands, and its dependencies. * **tsconfig.json** configures your project to use TypeScript. Most likely, you don't have to edit this file. [PreviousTerminology](https://developers.raycast.com/information/terminology) [NextManifest](https://developers.raycast.com/information/manifest) Last updated 6 months ago * [Sources](https://developers.raycast.com/information/file-structure#sources) * [Assets](https://developers.raycast.com/information/file-structure#assets) * [Support files](https://developers.raycast.com/information/file-structure#support-files) --- # Doppler Share Secrets | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/examples/doppler.md) . The full source code of the example can be found [here](https://github.com/raycast/extensions/tree/main/extensions/doppler-share-secrets#readme) . You can install the extension [here](https://www.raycast.com/thomas/doppler-share-secrets) . In this example we use a form to collect inputs from a user. To make it interesting, we use [Doppler](http://share.doppler.com/) which is a service to make it easy to securely share sensitive information such as API keys or passwords. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-b36017e7ee6ad8162b27712895ac0ac036103b4d%252Fexample-doppler-share-secrets.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=17749c74&sv=2) Example: Safely share secrets with Doppler The extension has multiple commands. In this example we're using a simple form with a textfield for the secret, a dropdown for an expiration after views and a second dropdown for an alternate expiration after a maximum of days. [](https://developers.raycast.com/examples/doppler#add-form-items) Add form items -------------------------------------------------------------------------------------- First, we render the static form. For this we add all the mentioned form items: Both dropdowns set the `storeValue` to true. This restores the last selected value when the command is opened again. This option is handy when your users select the same options often. In this case, we assume that users want to keep the expiration settings persisted. [](https://developers.raycast.com/examples/doppler#submit-form-values) Submit form values ---------------------------------------------------------------------------------------------- Now that we have the form, we want to collect the inserted values, send them to Doppler and copy the URL that allows us to share the information securely. For this, we create a new action: Let's break this down: * The `` returns an [``](https://developers.raycast.com/api-reference/user-interface/actions#action.submitform) . * The `handleSubmit()` gets called when the form is submitted with its values. * First we check if the user entered a secret. If not, we show a toast. * Then we show a toast to hint that there is a network call in progress to share the secret. * We call [Doppler's API](https://docs.doppler.com/reference/share-secret) with the form values * If the network response succeeds, we copy the authenticated URL to the clipboard and show a success toast. * If the network response fails, we show a failure toast with additional information about the failure. [](https://developers.raycast.com/examples/doppler#wire-it-up) Wire it up ------------------------------------------------------------------------------ The last step is to add the `` to the form: And there you go. A simple form to enter a secret and get a URL that you can share with others that will "destroy itself" accordingly to your preferences. As next steps, you could use the `` to paste the link directly to front-most application or add another action that clears the form and let's you create another shareable link. [PreviousCollaborate on Private Extensions](https://developers.raycast.com/teams/collaborate-on-private-extensions) [NextHacker News](https://developers.raycast.com/examples/hacker-news) Last updated 6 months ago * [Add form items](https://developers.raycast.com/examples/doppler#add-form-items) * [Submit form values](https://developers.raycast.com/examples/doppler#submit-form-values) * [Wire it up](https://developers.raycast.com/examples/doppler#wire-it-up) Copy import { Action, ActionPanel, Clipboard, Form, Icon, showToast, Toast } from "@raycast/api"; import got from "got"; export default function Command() { return (
); } Copy function ShareSecretAction() { async function handleSubmit(values: { secret: string; expireViews: number; expireDays: number }) { if (!values.secret) { showToast({ style: Toast.Style.Failure, title: "Secret is required", }); return; } const toast = await showToast({ style: Toast.Style.Animated, title: "Sharing secret", }); try { const { body } = await got.post("https://api.doppler.com/v1/share/secrets/plain", { json: { secret: values.secret, expire_views: values.expireViews, expire_days: values.expireDays, }, responseType: "json", }); await Clipboard.copy((body as any).authenticated_url); toast.style = Toast.Style.Success; toast.title = "Shared secret"; toast.message = "Copied link to clipboard"; } catch (error) { toast.style = Toast.Style.Failure; toast.title = "Failed sharing secret"; toast.message = String(error); } } return ; } Copy import { Action, ActionPanel, Clipboard, Form, Icon, showToast, Toast } from "@raycast/api"; import got from "got"; export default function Command() { return (
} > ); } function ShareSecretAction() { async function handleSubmit(values: { secret: string; expireViews: number; expireDays: number }) { if (!values.secret) { showToast({ style: Toast.Style.Failure, title: "Secret is required", }); return; } const toast = await showToast({ style: Toast.Style.Animated, title: "Sharing secret", }); try { const { body } = await got.post("https://api.doppler.com/v1/share/secrets/plain", { json: { secret: values.secret, expire_views: values.expireViews, expire_days: values.expireDays, }, responseType: "json", }); await Clipboard.copy((body as any).authenticated_url); toast.style = Toast.Style.Success; toast.title = "Shared secret"; toast.message = "Copied link to clipboard"; } catch (error) { toast.style = Toast.Style.Failure; toast.title = "Failed sharing secret"; toast.message = String(error); } } return ; } --- # Hacker News | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/examples/hacker-news.md) . The source code of the example can be found [here](https://github.com/raycast/extensions/tree/main/extensions/hacker-news#readme) . You can install it [here](https://www.raycast.com/thomas/hacker-news) . Who doesn't like a good morning read on [Hacker News](https://news.ycombinator.com/) with a warm coffee?! In this example, we create a simple list with the top stories on the frontpage. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-50ab2659c3f7430f15f90eb4dd6b7a6d6f0dd005%252Fexample-hacker-news.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=79d91fc2&sv=2) Example: Read frontpage of Hacker News [](https://developers.raycast.com/examples/hacker-news#load-top-stories) Load top stories ---------------------------------------------------------------------------------------------- First, let's get the latest top stories. For this we use a [RSS feed](https://hnrss.org/) : Breaking this down: * We use a third-party dependency to parse the RSS feed and initially the parser. * We define our command state as a TypeScript interface. * We use [React's `useEffect`](https://reactjs.org/docs/hooks-effect.html) hook to parse the RSS feed after the command did mount. * We print the top stories to the console. * We render a list and show the loading indicator as long as we load the stories. [](https://developers.raycast.com/examples/hacker-news#render-stories) Render stories ------------------------------------------------------------------------------------------ Now that we got the data from Hacker News, we want to render the stories. For this, we create a new React component and a few helper functions that render a story: To give the list item a nice look, we use a simple number emoji as icon, add the creator's name as subtitle and the points and comments as accessory title. Now we can render the ``: [](https://developers.raycast.com/examples/hacker-news#add-actions) Add actions ------------------------------------------------------------------------------------ When we select a story in the list, we want to be able to open it in the browser and also copy it's link so that we can share it in our watercooler Slack channel. For this, we create a new React Component: The component takes a story and renders an [``](https://developers.raycast.com/api-reference/user-interface/action-panel) with our required actions. We add the actions to the ``: [](https://developers.raycast.com/examples/hacker-news#handle-errors) Handle errors ---------------------------------------------------------------------------------------- Lastly, we want to be a good citizen and handle errors appropriately to guarantee a smooth experience. We'll show a toast whenever our network request fails: [](https://developers.raycast.com/examples/hacker-news#wrapping-up) Wrapping up ------------------------------------------------------------------------------------ That's it, you have a working extension to read the frontpage of Hacker News. As next steps, you can add another command to show the jobs feed or add an action to copy a Markdown formatted link. [PreviousDoppler Share Secrets](https://developers.raycast.com/examples/doppler) [NextTodo List](https://developers.raycast.com/examples/todo-list) Last updated 6 months ago * [Load top stories](https://developers.raycast.com/examples/hacker-news#load-top-stories) * [Render stories](https://developers.raycast.com/examples/hacker-news#render-stories) * [Add actions](https://developers.raycast.com/examples/hacker-news#add-actions) * [Handle errors](https://developers.raycast.com/examples/hacker-news#handle-errors) * [Wrapping up](https://developers.raycast.com/examples/hacker-news#wrapping-up) Copy import { Action, ActionPanel, List, showToast, Toast, Keyboard } from "@raycast/api"; import { useEffect, useState } from "react"; import Parser from "rss-parser"; const parser = new Parser(); interface State { items?: Parser.Item[]; error?: Error; } export default function Command() { const [state, setState] = useState({}); useEffect(() => { async function fetchStories() { try { const feed = await parser.parseURL("https://hnrss.org/frontpage?description=0&count=25"); setState({ items: feed.items }); } catch (error) { setState({ error: error instanceof Error ? error : new Error("Something went wrong"), }); } } fetchStories(); }, []); console.log(state.items); // Prints stories return ; } Copy function StoryListItem(props: { item: Parser.Item; index: number }) { const icon = getIcon(props.index + 1); const points = getPoints(props.item); const comments = getComments(props.item); return ( ); } const iconToEmojiMap = new Map([\ [1, "1️⃣"],\ [2, "2️⃣"],\ [3, "3️⃣"],\ [4, "4️⃣"],\ [5, "5️⃣"],\ [6, "6️⃣"],\ [7, "7️⃣"],\ [8, "8️⃣"],\ [9, "9️⃣"],\ [10, "πŸ”Ÿ"],\ ]); function getIcon(index: number) { return iconToEmojiMap.get(index) ?? "⏺"; } function getPoints(item: Parser.Item) { const matches = item.contentSnippet?.match(/(?<=Points:\s*)(\d+)/g); return matches?.[0]; } function getComments(item: Parser.Item) { const matches = item.contentSnippet?.match(/(?<=Comments:\s*)(\d+)/g); return matches?.[0]; } Copy export default function Command() { const [state, setState] = useState({}); // ... return ( {state.items?.map((item, index) => ( ))} ); } Copy function Actions(props: { item: Parser.Item }) { return ( {props.item.link && } {props.item.guid && } {props.item.link && ( )} ); } Copy function StoryListItem(props: { item: Parser.Item; index: number }) { // ... return ( } /> ); } Copy export default function Command() { const [state, setState] = useState({}); // ... if (state.error) { showToast({ style: Toast.Style.Failure, title: "Failed loading stories", message: state.error.message, }); } // ... } --- # Spotify Controls | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/examples/spotify-controls.md) . The source code of the example can be found [here](https://github.com/raycast/extensions/tree/main/extensions/spotify-controls#readme) . You can install it [here](https://www.raycast.com/thomas/spotify-controls) . This example shows how to build commands that don't show a UI in Raycast. This type of command is useful for interactions with other apps such as skipping songs in Spotify or just simply running some scripts that don't need visual confirmation. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-8a6b74f0afa581918036d18742c8c0e3baa4a37e%252Fexample-spotify-controls.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=f248f89f&sv=2) Example: Control the Spotify macOS app from Raycast [](https://developers.raycast.com/examples/spotify-controls#control-spotify-macos-app) Control Spotify macOS app --------------------------------------------------------------------------------------------------------------------- Spotify's macOS app supports AppleScript. This is great to control the app without opening it. For this, we use the [`run-applescript`](https://www.npmjs.com/package/run-applescript) package. Let's start by toggling play pause: [](https://developers.raycast.com/examples/spotify-controls#close-raycast-main-window) Close Raycast main window --------------------------------------------------------------------------------------------------------------------- When performing this command, you'll notice that Raycast toggles the play pause state of the Spotify macOS app but the Raycast main window stays open. Ideally the window closes after you run the command. Then you can carry on with what you did before. Here is how you can close the main window: Notice that we call the `closeMainWindow` function before running the AppleScript. This makes the command feel snappier. With less than 10 lines of code, you executed a script and controlled the UI of Raycast. As a next step you could add more commands to skip a track. [PreviousTodo List](https://developers.raycast.com/examples/todo-list) [NextTerminology](https://developers.raycast.com/information/terminology) Last updated 1 year ago * [Control Spotify macOS app](https://developers.raycast.com/examples/spotify-controls#control-spotify-macos-app) * [Close Raycast main window](https://developers.raycast.com/examples/spotify-controls#close-raycast-main-window) Copy import { runAppleScript } from "run-applescript"; export default async function Command() { await runAppleScript('tell application "Spotify" to playpause'); } Copy import { closeMainWindow } from "@raycast/api"; import { runAppleScript } from "run-applescript"; export default async function Command() { await closeMainWindow(); await runAppleScript('tell application "Spotify" to playpause'); } --- # Terminology | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/terminology.md) . [](https://developers.raycast.com/information/terminology#action) Action ----------------------------------------------------------------------------- Actions are accessible via the [Action Panel](https://developers.raycast.com/information/terminology#action-panel) in a [command](https://developers.raycast.com/information/terminology#command) . They are little functionality to control something; for example, to add a label to the selected GitHub issue, copy the link to a Linear issue, or anything else. Actions can have assigned keyboard shortcuts. [](https://developers.raycast.com/information/terminology#action-panel) Action Panel ----------------------------------------------------------------------------------------- Action Panel is located on the bottom right and can be opened with `⌘` `K`. It contains all currently available [actions](https://developers.raycast.com/information/terminology#action) and makes them easily discoverable. [](https://developers.raycast.com/information/terminology#ai-extensions) AI Extensions ------------------------------------------------------------------------------------------- AI Extensions are simply regular [extensions](https://developers.raycast.com/information/terminology#extension) that have [tools](https://developers.raycast.com/information/terminology#tool) . Once an extension has some tools, a user can `@mention` the extension in Quick AI, or the AI Commands, or the AI Chat. When doing so, the AI will have the opportunity to call one or multiple tools of the extensions mentioned. [](https://developers.raycast.com/information/terminology#command) Command ------------------------------------------------------------------------------- Commands are a type of entry point for an extension. Commands are available in the root search of Raycast. They can be a simple script or lists, forms, and more complex UI. [](https://developers.raycast.com/information/terminology#extension) Extension ----------------------------------------------------------------------------------- Extensions add functionality to Raycast. They consist of one or many [commands](https://developers.raycast.com/information/terminology#command) and can be installed from the Store. [](https://developers.raycast.com/information/terminology#manifest) Manifest --------------------------------------------------------------------------------- Manifest is the `package.json` file of an [extension](https://developers.raycast.com/information/terminology#extension) . It's an npm package mixed with Raycast specific metadata. The latter is necessary to identify the package for Raycast and publish it to the Store. [](https://developers.raycast.com/information/terminology#tool) Tool ------------------------------------------------------------------------- Tools are a type of entry point for an extension. As opposed to a [command](https://developers.raycast.com/information/terminology#command) , they don’t show up in the root search and the user can’t directly interact with them. Instead, they are functionalities that the AI can use to interact with an extension. [PreviousSpotify Controls](https://developers.raycast.com/examples/spotify-controls) [NextFile Structure](https://developers.raycast.com/information/file-structure) Last updated 1 year ago * [Action](https://developers.raycast.com/information/terminology#action) * [Action Panel](https://developers.raycast.com/information/terminology#action-panel) * [AI Extensions](https://developers.raycast.com/information/terminology#ai-extensions) * [Command](https://developers.raycast.com/information/terminology#command) * [Extension](https://developers.raycast.com/information/terminology#extension) * [Manifest](https://developers.raycast.com/information/terminology#manifest) * [Tool](https://developers.raycast.com/information/terminology#tool) --- # Deeplinks | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/lifecycle/deeplinks.md) . Deeplinks are Raycast-specific URLs you can use to launch any command, as long as it's installed and enabled in Raycast. They adhere to the following format: Copy raycast://extensions/// Name Description Type author-or-owner For store extensions, it's the value of the `owner` or the `author` field in the extension's [manifest](https://developers.raycast.com/information/manifest) . For built-in extensions (such as `Calendar`), this is always `raycast`. `string` extension-name For store extensions, it's the value of the extension's `name` field in the extension's [manifest](https://developers.raycast.com/information/manifest) . For built-in extensions (such as `Calendar`), this is the "slugified" extension name; in this case `calendar`. `string` command-name For store extensions, it's the value of the command's `name` field in the extension's [manifest](https://developers.raycast.com/information/manifest) . For built-in commands (such as `My Schedule`), this is the "slugified" command name; in this case `my-schedule`. `string` To make fetching a command's Deeplink easier, each command in the Raycast root now has a `Copy Deeplink` action. Whenever a command is launched using a Deeplink, Raycast will ask you to confirm that you want to run the command. This is to ensure that you are aware of the command you are running. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-612ba5e034fc166e1bc0f57d0035cf242bcf0011%252Fdeeplink-confirmation.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=d362e034&sv=2) [](https://developers.raycast.com/information/lifecycle/deeplinks#query-parameters) Query Parameters --------------------------------------------------------------------------------------------------------- Name Description Type launchType Runs the command in the background, skipping bringing Raycast to the front. Either `userInitiated` or `background` arguments If the command accepts [arguments](https://developers.raycast.com/information/lifecycle/arguments) , they can be passed using this query parameter. URL-encoded JSON object. context If the command make use of [LaunchContext](https://developers.raycast.com/api-reference/command#launchcontext) , it can be passed using this query parameter. URL-encoded JSON object. fallbackText Some text to prefill the search bar or first text input of the command `string` [PreviousBackground Refresh](https://developers.raycast.com/information/lifecycle/background-refresh) [NextBest Practices](https://developers.raycast.com/information/best-practices) Last updated 1 year ago --- # Todo List | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/examples/todo-list.md) . The source code of the example can be found [here](https://github.com/raycast/extensions/tree/main/examples/todo-list#readme) . What's an example section without a todo list?! Let's put one together in Raycast. This example will show how to render a list, navigate to a form to create a new element and update the list. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-9aaa862f82624bd327d69b52bca9de6f6e12dd13%252Fexample-todo-list.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=d823238c&sv=2) Example: A simple todo list [](https://developers.raycast.com/examples/todo-list#render-todo-list) Render todo list -------------------------------------------------------------------------------------------- Let's start with a set of todos and simply render them as a list in Raycast: For this we define a TypeScript interface to describe out Todo with a `title` and a `isCompleted` flag that we use later to complete the todo. We use [React's `useState` hook](https://reactjs.org/docs/hooks-state.html) to create a local state of our todos. This allows us to update them later and the list will get re-rendered. Lastly we render a list of all todos. [](https://developers.raycast.com/examples/todo-list#create-a-todo) Create a todo -------------------------------------------------------------------------------------- A static list of todos isn't that much fun. Let's create new ones with a form. For this, we create a new React component that renders the form: The `` shows a single text field for the title. When the form is submitted, it calls the `onCreate` callback and closes itself. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-d4c1ff50bde2708dfcf9875a92ab4d0a2a41ef53%252Fexample-create-todo.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=ee47c52a&sv=2) Create todo form To use the action, we add it to the `` component. This makes the action available when the list is empty which is exactly what we want to create our first todo. [](https://developers.raycast.com/examples/todo-list#complete-a-todo) Complete a todo ------------------------------------------------------------------------------------------ Now that we can create new todos, we also want to make sure that we can tick off something on our todo list. For this, we create a `` that we assign to the ``: In this case we added the `` to the list item. By doing this we can use the `index` to toggle the appropriate todo. We also added an icon to our todo that reflects the `isCompleted` state. [](https://developers.raycast.com/examples/todo-list#delete-a-todo) Delete a todo -------------------------------------------------------------------------------------- Similar to toggling a todo, we also add the possibility to delete one. You can follow the same steps and create a new `` and add it to the ``. We also gave the `` a keyboard shortcut. This way users can delete todos quicker. Additionally, we also added the `` to the ``. This makes sure that users can also create new todos when there are some already. Finally, our command looks like this: And that's a wrap. You created a todo list in Raycast, it's that easy. As next steps, you could extract the `` into a separate command. Then you can create todos also from the root search of Raycast and can even assign a global hotkey to open the form. Also, the todos aren't persisted. If you close the command and reopen it, they are gone. To persist, you can use the [storage](https://developers.raycast.com/api-reference/storage) or [write it to disc](https://developers.raycast.com/api-reference/environment#environment) . [PreviousHacker News](https://developers.raycast.com/examples/hacker-news) [NextSpotify Controls](https://developers.raycast.com/examples/spotify-controls) Last updated 1 year ago * [Render todo list](https://developers.raycast.com/examples/todo-list#render-todo-list) * [Create a todo](https://developers.raycast.com/examples/todo-list#create-a-todo) * [Complete a todo](https://developers.raycast.com/examples/todo-list#complete-a-todo) * [Delete a todo](https://developers.raycast.com/examples/todo-list#delete-a-todo) Copy import { List } from "@raycast/api"; import { useState } from "react"; interface Todo { title: string; isCompleted: boolean; } export default function Command() { const [todos, setTodos] = useState([\ { title: "Write a todo list extension", isCompleted: false },\ { title: "Explain it to others", isCompleted: false },\ ]); return ( {todos.map((todo, index) => ( ))} ); } Copy function CreateTodoForm(props: { onCreate: (todo: Todo) => void }) { const { pop } = useNavigation(); function handleSubmit(values: { title: string }) { props.onCreate({ title: values.title, isCompleted: false }); pop(); } return (
} > ); } function CreateTodoAction(props: { onCreate: (todo: Todo) => void }) { return ( } /> ); } Copy export default function Command() { const [todos, setTodos] = useState([]); function handleCreate(todo: Todo) { const newTodos = [...todos, todo]; setTodos(newTodos); } return (
} > {todos.map((todo, index) => ( ))} ); } Copy export default function Command() { const [todos, setTodos] = useState([]); // ... function handleToggle(index: number) { const newTodos = [...todos]; newTodos[index].isCompleted = !newTodos[index].isCompleted; setTodos(newTodos); } return ( } > {todos.map((todo, index) => ( handleToggle(index)} /> } /> ))} ); } function ToggleTodoAction(props: { todo: Todo; onToggle: () => void }) { return ( ); } Copy export default function Command() { const [todos, setTodos] = useState([]); // ... function handleDelete(index: number) { const newTodos = [...todos]; newTodos.splice(index, 1); setTodos(newTodos); } return ( } > {todos.map((todo, index) => ( handleToggle(index)} /> handleDelete(index)} /> } /> ))} ); } // ... function DeleteTodoAction(props: { onDelete: () => void }) { return ( ); } Copy import { Action, ActionPanel, Form, Icon, List, useNavigation } from "@raycast/api"; import { useState } from "react"; interface Todo { title: string; isCompleted: boolean; } export default function Command() { const [todos, setTodos] = useState([\ { title: "Write a todo list extension", isCompleted: false },\ { title: "Explain it to others", isCompleted: false },\ ]); function handleCreate(todo: Todo) { const newTodos = [...todos, todo]; setTodos(newTodos); } function handleToggle(index: number) { const newTodos = [...todos]; newTodos[index].isCompleted = !newTodos[index].isCompleted; setTodos(newTodos); } function handleDelete(index: number) { const newTodos = [...todos]; newTodos.splice(index, 1); setTodos(newTodos); } return ( } > {todos.map((todo, index) => ( handleToggle(index)} /> handleDelete(index)} /> } /> ))} ); } function CreateTodoForm(props: { onCreate: (todo: Todo) => void }) { const { pop } = useNavigation(); function handleSubmit(values: { title: string }) { props.onCreate({ title: values.title, isCompleted: false }); pop(); } return (
} > ); } function CreateTodoAction(props: { onCreate: (todo: Todo) => void }) { return ( } /> ); } function ToggleTodoAction(props: { todo: Todo; onToggle: () => void }) { return ( ); } function DeleteTodoAction(props: { onDelete: () => void }) { return ( ); } --- # Lifecycle | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/lifecycle.md) . A command is typically launched, runs for a while, and then is unloaded. [](https://developers.raycast.com/information/lifecycle#launch) Launch --------------------------------------------------------------------------- When a command is launched in Raycast, the command code is executed right away. If the extension exports a default function, this function will automatically be called. If you return a React component in the exported default function, it will automatically be rendered as the root component. For commands that don't need a user interface (`mode` property set to "`no-view"` in the manifest), you can export an async function and perform API methods using async/await. View Command No-View Command Copy import { Detail } from "@raycast/api"; // Returns the main React component for a view command export default function Command() { return ; } Copy import { showHUD } from "@raycast/api"; // Runs async. code in a no-view command export default async function Command() { await showHUD("Hello"); } There are different ways to launch a command: * The user searches for the command in the root search and executes it. * The user registers an alias for the command and presses it. * Another command launches the command _via_ [`launchCommand`](https://developers.raycast.com/api-reference/command#launchcommand) . * The command was launched in the [background](https://developers.raycast.com/information/lifecycle/background-refresh) . * A [Form's Draft](https://developers.raycast.com/api-reference/user-interface/form#drafts) was saved and the user executes it. * A user registers the command as a [fallback command](https://manual.raycast.com/v1/fallback-commands) and executes it when there are no results in the root search. * A user clicks a [Deeplink](https://developers.raycast.com/information/lifecycle/deeplinks) Depending on how the command was launched, different arguments will be passed to the exported default function. ### [](https://developers.raycast.com/information/lifecycle#launchprops) LaunchProps Property Description Type arguments\* Use these values to populate the initial state for your command. [`Arguments`](https://developers.raycast.com/information/lifecycle/arguments#arguments) launchType\* The type of launch for the command (user initiated or background). [`LaunchType`](https://developers.raycast.com/api-reference/environment#launchtype) draftValues When a user enters the command via a draft, this object will contain the user inputs that were saved as a draft. Use its values to populate the initial state for your Form. [`Form.Values`](https://developers.raycast.com/api-reference/user-interface/form#form.values) fallbackText When the command is launched as a fallback command, this string contains the text of the root search. `string` launchContext When the command is launched programmatically via `launchCommand`, this object contains the value passed to `context`. [`LaunchContext`](https://developers.raycast.com/api-reference/command#launchcontext) [](https://developers.raycast.com/information/lifecycle#unloading) Unloading --------------------------------------------------------------------------------- When the command is unloaded (typically by popping back to root search for view commands or after the script finishes for no-view commands), Raycast unloads the entire command from memory. Note that there are memory limits for commands, and if those limits are exceeded, the command gets terminated, and users will see an error message. [PreviousManifest](https://developers.raycast.com/information/manifest) [NextArguments](https://developers.raycast.com/information/lifecycle/arguments) Last updated 2 months ago * [Launch](https://developers.raycast.com/information/lifecycle#launch) * [LaunchProps](https://developers.raycast.com/information/lifecycle#launchprops) * [Unloading](https://developers.raycast.com/information/lifecycle#unloading) Copy import { Detail, LaunchProps } from "@raycast/api"; // Access the different launch properties via the argument passed to the function export default function Command(props: LaunchProps) { return ; } --- # Arguments | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/lifecycle/arguments.md) . Raycast supports arguments for your commands so that users can enter values right from Root Search before opening the command. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-5820d335065ed715429f3d7c0ab5edff00c9182a%252Farguments.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=b22f5e3c&sv=2) Arguments are configured in the [manifest](https://developers.raycast.com/information/manifest#argument-properties) per command. * **Maximum number of arguments:** 3 (if you have a use case that requires more, please let us know via feedback or in the [Slack community](https://www.raycast.com/community) ) * The order of the arguments specified in the manifest is important and is reflected by the fields shown in Root Search. To provide a better UX, put the required arguments before the optional ones. [](https://developers.raycast.com/information/lifecycle/arguments#example) Example --------------------------------------------------------------------------------------- Let's say we want a command with three arguments. Its `package.json` will look like this: The command itself will receive the arguments' values via the `arguments` prop: [](https://developers.raycast.com/information/lifecycle/arguments#types) Types ----------------------------------------------------------------------------------- ### [](https://developers.raycast.com/information/lifecycle/arguments#arguments) Arguments A command receives the values of its arguments via a top-level prop named `arguments`. It is an object with the arguments' `name` as keys and their values as the property's values. Depending on the `type` of the argument, the type of its value will be different. Argument type Value type `text` `string` `password` `string` `dropdown` `string` Raycast provides a global TypeScript namespace called `Arguments` which contains the types of the arguments of all the commands of the extension. For example, if a command named `show-todos` accepts arguments, its `LaunchProps` can be described as `LaunchProps<{ arguments: Arguments.ShowTodos }>`. This will make sure that the types used in the command stay in sync with the manifest. [PreviousLifecycle](https://developers.raycast.com/information/lifecycle) [NextBackground Refresh](https://developers.raycast.com/information/lifecycle/background-refresh) Last updated 1 year ago * [Example](https://developers.raycast.com/information/lifecycle/arguments#example) * [Types](https://developers.raycast.com/information/lifecycle/arguments#types) * [Arguments](https://developers.raycast.com/information/lifecycle/arguments#arguments) Copy { "name": "arguments", "title": "API Arguments", "description": "Example of Arguments usage in the API", "icon": "command-icon.png", "author": "raycast", "license": "MIT", "commands": [\ {\ "name": "my-command",\ "title": "Arguments",\ "subtitle": "API Examples",\ "description": "Demonstrates usage of arguments",\ "mode": "view",\ "arguments": [\ {\ "name": "title",\ "placeholder": "Title",\ "type": "text",\ "required": true\ },\ {\ "name": "subtitle",\ "placeholder": "Secret Subtitle",\ "type": "password"\ },\ {\ "name": "favoriteColor",\ "type": "dropdown",\ "placeholder": "Favorite Color",\ "required": true,\ "data": [\ {\ "title": "Red",\ "value": "red"\ },\ {\ "title": "Green",\ "value": "green"\ },\ {\ "title": "Blue",\ "value": "blue"\ }\ ]\ }\ ]\ }\ ], "dependencies": { "@raycast/api": "1.38.0" }, "scripts": { "dev": "ray develop", "build": "ray build -e dist", "lint": "ray lint" } } Copy import { Form, LaunchProps } from "@raycast/api"; export default function Todoist(props: LaunchProps<{ arguments: Arguments.MyCommand }>) { const { title, subtitle } = props.arguments; console.log(`title: ${title}, subtitle: ${subtitle}`); return (
); } --- # Background Refresh | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/lifecycle/background-refresh.md) . Commands of an extension can be configured to be automatically run in the background, without the user manually opening them. Background refresh can be useful for: * dynamically updating the subtitle of a command in Raycast root search * refreshing menu bar commands * other supporting functionality for your main commands This guide helps you understand when and how to use background refresh and learn about the constraints. [](https://developers.raycast.com/information/lifecycle/background-refresh#scheduling-commands) Scheduling Commands ------------------------------------------------------------------------------------------------------------------------ Raycast supports scheduling commands with mode `no-view` and `menu-bar` at a configured interval. ### [](https://developers.raycast.com/information/lifecycle/background-refresh#manifest) Manifest Add a new property `interval` to a command in the [manifest](https://developers.raycast.com/information/manifest#command-properties) Example: Copy { "name": "unread-notifications", "title": "Show Unread Notifications", "description": "Shows the number of unread notifications in root search", "mode": "no-view", "interval": "10m" }, The interval specifies that the command should be launched in the background every X seconds (s), minutes (m), hours (h) or days (d). Examples: `10m`, `12h`, `1d`. The minimum value is 10 seconds (`10s`), which should be used cautiously, also see the section on best practices. Note that the actual scheduling is not exact and might vary within a tolerance level. macOS determines the best time for running the command in order to optimize energy consumption, and scheduling times can also vary when running on battery. To prevent overlapping background launches of the same command, commands are terminated after a timeout that is dynamically adjusted to the interval. [](https://developers.raycast.com/information/lifecycle/background-refresh#running-in-the-background) Running in the background ------------------------------------------------------------------------------------------------------------------------------------ The entry point of your command stays the same when launched from the background. For no-view commands, a command will run until the Promise of the main async function resolves. Menu bar commands render a React component and run until the `isLoading` property is set to `false`. You can use the global `environment.launchType` in your command to determine whether the command has been launched by the user (`LaunchType.UserInitiated`) or via background refresh (`LaunchType.Background`). Raycast auto-terminates the command if it exceeds its maximum execution time. If your command saves some state that is shared with other commands, make sure to use defensive programming, i.e. add handling for errors and data races if the stored state is incomplete or inaccessible. [](https://developers.raycast.com/information/lifecycle/background-refresh#development-and-debugging) Development and Debugging ------------------------------------------------------------------------------------------------------------------------------------ For local commands under development, errors are shown as usual via the console. Two developer actions in root search help you to run and debug scheduled commands: * Run in Background: this immediately runs the command with `environment.launchType` set to `LaunchType.Background`. * Show Error: if the command could not be loaded or an uncaught runtime exception was thrown, the full error can be shown in the Raycast error overlay for development. This action is also shown to users of the installed Store command and provides actions to copy and report the error on the production error overlay. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-f56fdf8a10d8451837247c60012963ab7db7c947%252Fbackground-refresh-error.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=4a16c805&sv=2) When the background run leads to an error, users will also see a warning icon on the root search command and a tooltip with a hint to show the error via the Action Panel. The tooltip over the subtitle of a command shows the last run time. You can launch the built-in root search command "Extension Diagnostics" to see which of your commands run in background and when they last ran. [](https://developers.raycast.com/information/lifecycle/background-refresh#preferences) Preferences -------------------------------------------------------------------------------------------------------- For scheduled commands, Raycast automatically adds command preferences that give users the options to enable and disable background refresh. Preferences also show the last run time of the command. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-475411d88fef4886f8a3f30521b5dedf3f8b4afc%252Fbackground-refresh-preferences.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=b8188300&sv=2) When a user installs the command via the Store, background refresh is initially _disabled_ and is activated either when the user opens the command for the first time or enables background refresh in preferences. (This is to avoid automatically running commands in the background without the user being aware of it.) [](https://developers.raycast.com/information/lifecycle/background-refresh#best-practices) Best Practices -------------------------------------------------------------------------------------------------------------- * Make sure the command is useful both when manually launched by the user or when launched in the background * Choose the interval value as high as possible - low values mean the command will run more often and consume more energy * If your command performs network requests, check the rate limits of the service and handle errors appropriately (e.g. automatically retry later) * Make sure the command finishes as quickly as possible; for menu bar commands, ensure `isLoading` is set to false as early as possible * Use defensive programming if state is shared between commands of an extension and handle potential data races and inaccessible data [PreviousArguments](https://developers.raycast.com/information/lifecycle/arguments) [NextDeeplinks](https://developers.raycast.com/information/lifecycle/deeplinks) Last updated 1 year ago * [Scheduling Commands](https://developers.raycast.com/information/lifecycle/background-refresh#scheduling-commands) * [Manifest](https://developers.raycast.com/information/lifecycle/background-refresh#manifest) * [Running in the background](https://developers.raycast.com/information/lifecycle/background-refresh#running-in-the-background) * [Development and Debugging](https://developers.raycast.com/information/lifecycle/background-refresh#development-and-debugging) * [Preferences](https://developers.raycast.com/information/lifecycle/background-refresh#preferences) * [Best Practices](https://developers.raycast.com/information/lifecycle/background-refresh#best-practices) Copy import { environment, updateCommandMetadata } from "@raycast/api"; async function fetchUnreadNotificationCount() { return 10; } export default async function Command() { console.log("launchType", environment.launchType); const count = await fetchUnreadNotificationCount(); await updateCommandMetadata({ subtitle: `Unread Notifications: ${count}` }); } --- # Manage Extensions Command | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/developer-tools/manage-extensions-command.md) . Raycast provides a built-in command to manage your extensions. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-98a70fc3a77ad10cc32267b282a16b49a38abc00%252Fmanage-extensions.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=a58042f9&sv=2) For each extensions, there are a few actions to manage them. [](https://developers.raycast.com/information/developer-tools/manage-extensions-command#add-new-command) Add New Command ----------------------------------------------------------------------------------------------------------------------------- One such action is the `Add New Command` action. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-5843ab46283de8d365e94b4c04a36e11cf930344%252Fadd-new-command.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=5045563f&sv=2) It will prompt you for the information about the new command before updating the manifest of the extension and creating the file for you based on the template you selected. [PreviousDeveloper Tools](https://developers.raycast.com/information/developer-tools) [NextCLI](https://developers.raycast.com/information/developer-tools/cli) Last updated 1 year ago --- # Versioning | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/versioning.md) . Versioning your extensions is straightforward since we've designed the system in a way that **frees you from having to deal with versioning schemes and compatibility**. The model is similar to that of app stores where there's only one implicit _latest_ version that will be updated when the extension is published in the store. Extensions are automatically updated for end users. [](https://developers.raycast.com/information/versioning#development) Development -------------------------------------------------------------------------------------- For **development**, this means that you do _not_ declare a version property in the manifest. If you wish to use API features that were added in a later version, you just update your `@raycast/api` npm dependency, start using the feature, and submit an extension update to the store. [](https://developers.raycast.com/information/versioning#end-users) End Users ---------------------------------------------------------------------------------- For **end-users** installing or updating your extension, Raycast automatically checks the compatibility between the API version that the extension actually uses and the user's current Raycast app version (which contains the API runtime and also manages the Node version). If there's a compatibility mismatch such as the user not having the required latest Raycast app version, we show a hint and prompt the user to update Raycast so that the next compatibility check succeeds. [](https://developers.raycast.com/information/versioning#version-history) Version History ---------------------------------------------------------------------------------------------- Optionally, you can provide a `changelog.md` file in your extension, and give detailed changes with every update. These changes can be viewed by the user on the extension details screen, under Version History, as well as on the [raycast.com/store](https://raycast.com/store) . You can learn more about Version History [here](https://developers.raycast.com/basics/prepare-an-extension-for-store#version-history) , how to add it to your extension, and the required format for the best appearance. [](https://developers.raycast.com/information/versioning#api-evolution) API Evolution ------------------------------------------------------------------------------------------ Generally, we follow an **API evolution** process, meaning that we stay backward-compatible and do not introduce breaking changes within the same major API version. We'll 1) add new functionality and 2) we'll mark certain API methods and components as _deprecated_ over time, which signals to you that you should stop using those features and migrate to the new recommended alternatives. At some point in the future, we may introduce a new breaking major release; however, at this time, you will be notified, and there will be a transition period for migrating extensions. [PreviousSecurity](https://developers.raycast.com/information/security) [NextAI](https://developers.raycast.com/api-reference/ai) Last updated 3 years ago * [Development](https://developers.raycast.com/information/versioning#development) * [End Users](https://developers.raycast.com/information/versioning#end-users) * [Version History](https://developers.raycast.com/information/versioning#version-history) * [API Evolution](https://developers.raycast.com/information/versioning#api-evolution) --- # Manifest | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/manifest.md) . The `package.json` manifest file is a superset of npm's `package.json` file. This way, you only need one file to configure your extension. This document covers only the Raycast specific fields. Refer to [npm's documentation](https://docs.npmjs.com/cli/v7/configuring-npm/package-json) for everything else. Here is a typical manifest file: Copy { "name": "my-extension", "title": "My Extension", "description": "My extension that can do a lot of things", "icon": "icon.png", "author": "thomas", "platforms": ["macOS", "Windows"], "categories": ["Fun", "Communication"], "license": "MIT", "commands": [\ {\ "name": "index",\ "title": "Send Love",\ "description": "A command to send love to each other",\ "mode": "view"\ }\ ] } [](https://developers.raycast.com/information/manifest#extension-properties) Extension properties ------------------------------------------------------------------------------------------------------ All Raycast related properties for an extension. Property Description name\* A unique name for the extension. This is used in the Store link to your extension, so keep it short and URL compatible. title\* The title of the extension that is shown to the user in the Store as well as the preferences. Use this title to describe your extension well that users can find it in the Store. description\* The full description of the extension shown in the Store. icon\* A reference to an icon file in the assets folder. Use png format with a size of 512 x 512 pixels. To support light and dark theme, add two icons, one with `@dark` as suffix, e.g. `icon.png` and `icon@dark.png`. author \* Your Raycast Store handle (username) platforms \* An Array of platforms supported by the extension(`"macOS"` or `"Windows"`). If the extension uses some platform-specific APIs, restrict which platform can install it. categories\* An array of categories that your extension belongs in. commands\* An array of [commands](https://developers.raycast.com/information/terminology#command) exposed by the extension, see [Command properties](https://developers.raycast.com/information/manifest#command-properties) . tools An array of tools that the AI can use to interact with this extension, see [Tool properties](https://developers.raycast.com/information/manifest#tool-properties) . ai Additional information related to the AI capabilities of the extension, see [AI properties](https://developers.raycast.com/information/manifest#ai-properties) . owner Used for extensions published under an organisation. When defined, the extension will be [private](https://developers.raycast.com/teams/getting-started) (except when specifying `access`). access Either `"public"` or `"private"`. Public extensions are downloadable by anybody, while [private](https://developers.raycast.com/teams/getting-started) extensions can only be downloaded by a member of a given organization. contributors An array of Raycast store handles (usernames) of people who have meaningfully contributed and are maintaining to this extension. pastContributors An array of Raycast store handles (usernames) of people who have meaningfully contributed to the extension's commands but do not maintain it anymore. keywords An array of keywords for which the extension can be searched for in the Store. preferences Extensions can contribute preferences that are shown in Raycast Preferences > Extensions. You can use preferences for configuration values and passwords or personal access tokens, see [Preference properties](https://developers.raycast.com/information/manifest#preference-properties) . external An Array of package or file names that should be excluded from the build. The package will not be bundled, but the import is preserved and will be evaluated at runtime. [](https://developers.raycast.com/information/manifest#command-properties) Command properties -------------------------------------------------------------------------------------------------- All properties for a [command](https://developers.raycast.com/information/terminology#command) . Property Description name\* A unique id for the command. The name directly maps to the entry point file for the command. So a command named "index" would map to `src/index.ts` (or any other supported TypeScript or JavaScript file extension such as `.tsx`, `.js`, `.jsx`). title\* The display name of the command, shown to the user in the Store, Preferences, and in Raycast's root search. subtitle The optional subtitle of the command in the root search. Usually, this is the service or domain that your command is associated with. You can dynamically update this property using [`updateCommandMetadata`](https://developers.raycast.com/api-reference/command#updatecommandmetadata) . description\* It helps users understand what the command does. It will be displayed in the Store and in Preferences. icon An optional reference to an icon file in the assets folder. Use png format with a size of at least 512 x 512 pixels. To support light and dark theme, add two icons, one with `@dark` as suffix, e.g. `icon.png` and `icon@dark.png`. If no icon is specified, the extension icon will be used. mode\* A value of `view` indicates that the command will show a main view when performed. `no-view` means that the command does not push a view to the main navigation stack in Raycast. The latter is handy for directly opening a URL or other API functionalities that don't require a user interface. `menu-bar` indicates that this command will return a [Menu Bar Extra](https://developers.raycast.com/api-reference/menu-bar-commands) interval The value specifies that a `no-view` or `menu-bar` command should be launched in the background every X seconds (s), minutes (m), hours (h) or days (d). Examples: 90s, 1m, 12h, 1d. The minimum value is 1 minute (1m). keywords An optional array of keywords for which the command can be searched in Raycast. arguments An optional array of arguments that are requested from user when the command is called, see [Argument properties](https://developers.raycast.com/information/manifest#argument-properties) . preferences Commands can optionally contribute preferences that are shown in Raycast Preferences > Extensions when selecting the command. You can use preferences for configuration values and passwords or personal access tokens, see [Preference properties](https://developers.raycast.com/information/manifest#preference-properties) . Commands automatically "inherit" extension preferences and can also override entries with the same `name`. disabledByDefault Specify whether the command should be enabled by default or not. By default, all commands are enabled but there are some cases where you might want to include additional commands and let the user enable them if they need it. _Note that this flag is only used when installing a new extension or when there is a new command._ [](https://developers.raycast.com/information/manifest#preference-properties) Preference properties -------------------------------------------------------------------------------------------------------- All properties for extension or command-specific preferences. Use the [Preferences API](https://developers.raycast.com/api-reference/preferences) to access their values. Property Description name\* A unique id for the preference. title\* The display name of the preference shown in Raycast preferences. For `"checkbox"`, `"textfield"` and `"password"`, it is shown as a section title above the respective input element. If you want to group multiple checkboxes into a single section, set the `title` of the first checkbox and leave the `title` of the other checkboxes empty. description\* It helps users understand what the preference does. It will be displayed as a tooltip when hovering over it. type\* The preference type. We currently support `"textfield"` and `"password"` (for secure entry), `"checkbox"`, `"dropdown"`, `"appPicker"`, `"file"`, and `"directory"`. required\* Indicates whether the value is required and must be entered by the user before the extension is usable. placeholder Text displayed in the preference's field when no value has been input. default The optional default value for the field. For textfields, this is a string value; for checkboxes a boolean; for dropdowns the value of an object in the data array; for appPickers an application name, bundle ID or path. Additionally, you can specify a different value per plaform by passing an object: `{ "macOS": ..., "Windows": ... }`. Depending on the `type` of the Preference, some additional properties can be required: ### [](https://developers.raycast.com/information/manifest#additional-properties-for-checkbox-preference) Additional properties for `checkbox` Preference Property Description label\* The label of the checkbox. Shown next to the checkbox. ### [](https://developers.raycast.com/information/manifest#additional-properties-for-dropdown-preference) Additional properties for `dropdown` Preference Property Description data\* An array of objects with `title` and `value` properties, e.g.: `[{"title": "Item 1", "value": "1"}]` [](https://developers.raycast.com/information/manifest#argument-properties) Argument properties ---------------------------------------------------------------------------------------------------- All properties for command arguments. Use the [Arguments API](https://developers.raycast.com/information/lifecycle/arguments) to access their values. Property Description name\* A unique id for the argument. This value will be used to as the key in the object passed as [top-level prop](https://developers.raycast.com/information/lifecycle/arguments#arguments) . type\* The argument type. We currently support `"text"`, `"password"` (for secure entry), and `"dropdown"`. When the type is `password`, entered text will be replaced with asterisks. Most common use case – passing passwords or secrets to commands. placeholder\* Placeholder for the argument's input field. required Indicates whether the value is required and must be entered by the user before the command is opened. Default value for this is `false`. Depending on the `type` of the Argument, some additional properties can be required: ### [](https://developers.raycast.com/information/manifest#additional-properties-for-dropdown-argument) Additional properties for `dropdown` Argument Property Description data\* An array of objects with `title` and `value` properties, e.g.: `[{"title": "Item 1", "value": "1"}]` [](https://developers.raycast.com/information/manifest#tool-properties) Tool Properties -------------------------------------------------------------------------------------------- All properties for a tool. Property Description name\* A unique id for the tool. The name directly maps to the entry point file for the tool. So a tool named "index" would map to `src/tools/index.ts` (or any other supported TypeScript file extension such as `.tsx`). title\* The display name of the tool, shown to the user in the Store and Preferences. description\* It helps users and the AI understand what the tool does. It will be displayed in the Store and in Preferences. icon An optional reference to an icon file in the assets folder. Use png format with a size of at least 512 x 512 pixels. To support light and dark theme, add two icons, one with `@dark` as suffix, e.g. `icon.png` and `icon@dark.png`. If no icon is specified, the extension icon will be used. [](https://developers.raycast.com/information/manifest#ai-properties) AI Properties ---------------------------------------------------------------------------------------- All properties for the AI capabilities of the extension. This object should be written in a `ai.yaml` file at the root of the extension. Property Description instructions A string containing additional instructions for the AI. It will be added as a system message whenever the extension is mentioned. It can for example be used to help the AI respond with a format that makes more sense for the extension: `Always format pull requests and issues as markdown links: [pull-request-title](https://github.com/:org/:repo/pull/:number) and [issue-title](https://github.com/:org/:repo/issues/:number)` evals Evals for AI Extension. [More details](https://raycastapp.notion.site/AI-Extensions-Evals-15fd6e4a8215800598cad77d8afb5dc8?pvs=73) [PreviousFile Structure](https://developers.raycast.com/information/file-structure) [NextLifecycle](https://developers.raycast.com/information/lifecycle) Last updated 3 months ago * [Extension properties](https://developers.raycast.com/information/manifest#extension-properties) * [Command properties](https://developers.raycast.com/information/manifest#command-properties) * [Preference properties](https://developers.raycast.com/information/manifest#preference-properties) * [Additional properties for checkbox Preference](https://developers.raycast.com/information/manifest#additional-properties-for-checkbox-preference) * [Additional properties for dropdown Preference](https://developers.raycast.com/information/manifest#additional-properties-for-dropdown-preference) * [Argument properties](https://developers.raycast.com/information/manifest#argument-properties) * [Additional properties for dropdown Argument](https://developers.raycast.com/information/manifest#additional-properties-for-dropdown-argument) * [Tool Properties](https://developers.raycast.com/information/manifest#tool-properties) * [AI Properties](https://developers.raycast.com/information/manifest#ai-properties) --- # CLI | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/developer-tools/cli.md) . The CLI is part of the `@raycast/api` package and is automatically installed in your extension directory during setup. To get a list of the available CLI commands, run the following command inside your extension directory: Copy npx ray help [](https://developers.raycast.com/information/developer-tools/cli#build) Build ----------------------------------------------------------------------------------- `npx ray build` creates an optimized production build of your extension for distribution. This command is used by our CI to publish your extension to the store. You can use `npx ray build -e dist` to validate that your extension builds properly. [](https://developers.raycast.com/information/developer-tools/cli#development) Development ----------------------------------------------------------------------------------------------- `npx ray develop` starts your extension in development mode. The mode includes the following: * Extension shows up at the top of the root search for quick access * Commands get automatically reloaded when you save your changes (you can toggle auto-reloading via Raycast Preferences > Advanced > "Auto-reload on save") * Error overlays include detailed stack traces for faster debugging * Log messages are displayed in the terminal * Status indicator is visible in the navigation title of the command to signal build errors * Imports the extension to Raycast if it wasn't before [](https://developers.raycast.com/information/developer-tools/cli#lint) Lint --------------------------------------------------------------------------------- `npx ray lint` runs [ESLint](http://eslint.org/) for all files in the `src` directory. [](https://developers.raycast.com/information/developer-tools/cli#migrate) Migrate --------------------------------------------------------------------------------------- `npx ray migrate` [migrates](https://developers.raycast.com/misc/migration) your extension to the latest version of the `@raycast/api`. [](https://developers.raycast.com/information/developer-tools/cli#publish) Publish --------------------------------------------------------------------------------------- `npx ray publish` verifies, builds, and publishes an extension. If the extension is private (eg. has an `owner` and no public `access`), it will be published to the organization's private store. This command is only available to users that are part of that organization. Learn more about it [here](https://developers.raycast.com/teams/getting-started) . [PreviousManage Extensions Command](https://developers.raycast.com/information/developer-tools/manage-extensions-command) [NextESLint](https://developers.raycast.com/information/developer-tools/eslint) Last updated 1 year ago * [Build](https://developers.raycast.com/information/developer-tools/cli#build) * [Development](https://developers.raycast.com/information/developer-tools/cli#development) * [Lint](https://developers.raycast.com/information/developer-tools/cli#lint) * [Migrate](https://developers.raycast.com/information/developer-tools/cli#migrate) * [Publish](https://developers.raycast.com/information/developer-tools/cli#publish) --- # Security | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/security.md) . Note that this is _not_ a guide on how to create secure Raycast extensions but rather an overview of security-related aspects on how extensions are built, distributed and run. [](https://developers.raycast.com/information/security#raycast) Raycast ---------------------------------------------------------------------------- Raycast itself runs outside of the App Store as "Developer ID Application", **signed** with the Raycast certificate and verified by Apple's **notarization service** before the app is distributed. Raycast provides various commands that interact with OS-level functionality, some of which prompt the user for granting **permissions** when required. The app is **automatically kept up-to-date** to minimize the risk of running heavily outdated versions and to ship hotfixes quickly. Raycast is a local-first application that stores user data in a local **encrypted database**, makes use of the system **Keychain** where secure data is stored, and generally connects to third-party APIs directly rather than proxying data through Raycast servers. [](https://developers.raycast.com/information/security#publishing-process) Publishing Process -------------------------------------------------------------------------------------------------- All extensions are **open source** so the current source code can be inspected at all times. Before an extension gets merged into the **public repository**, members from Raycast and the community collaboratively **review** extensions, and follow our **store guidelines**. After the code review, the Continuous Integration system performs a set of **validations** to make sure that manifest conforms to the defined schema, required assets have the correct format, the author is valid, and no build and type errors are present. (More CI pipeline tooling for automated static security analysis is planned.) The built extension is then **archived and uploaded** to the Raycast Store, and eventually published for a registered user account. When an extension is installed or updated, the extension is downloaded from the store, unarchived to disk, and a record is updated in the local Raycast database. End-users install extensions through the built-in store or the web store. [](https://developers.raycast.com/information/security#runtime-model) Runtime Model ---------------------------------------------------------------------------------------- In order to run extensions, Raycast launches a **single child Node.js process** where extensions get loaded and unloaded as needed; inter-process communication with Raycast happens through standard file handles and a thin RPC protocol that only exposes a **defined set of APIs**, that is, an extension cannot just perform any Raycast operation. The **Node runtime is managed** by Raycast and automatically downloaded to the user's machine. We use an official version and **verify the Node binary** to ensure it has not been tampered with. An extension runs in its own **v8 isolate** (worker thread) and gets its own event loop, JavaScript engine and Node instance, and limited heap memory. That way, we ensure **isolation between extensions** when future Raycast versions may support background executions of multiple extensions running concurrently. [](https://developers.raycast.com/information/security#permissions) Permissions ------------------------------------------------------------------------------------ Extensions are **not further sandboxed** as far as policies for file I/O, networking, or other features of the Node runtime are concerned; this might change in the future as we want to carefully balance user/developer experience and security needs. By default and similar to other macOS apps, accessing special directories such as the user Documents directory or performing screen recording first requires users to give **permissions** to Raycast (parent process) via the **macOS Security & Preferences** pane, otherwise programmatic access is not permitted. [](https://developers.raycast.com/information/security#data-storage) Data Storage -------------------------------------------------------------------------------------- While extensions can access the file system and use their own methods of storing and accessing data, Raycast provides **APIs for securely storing data**: _password_ preferences can be used to ask users for values such as access tokens, and the local storage APIs provide methods for reading and writing data payloads. In both cases, the data is stored in the local encrypted database and can only be accessed by the corresponding extension. [](https://developers.raycast.com/information/security#automatic-updates) Automatic Updates ------------------------------------------------------------------------------------------------ Both Raycast itself and extensions are **automatically updated** and we think of this as a security feature since countless exploits have happened due to outdated and vulnerable software. Our goal is that neither developers nor end-users need to worry about versions, and we **minimize the time from update to distribution** to end-users. [PreviousTemplates](https://developers.raycast.com/information/developer-tools/templates) [NextVersioning](https://developers.raycast.com/information/versioning) Last updated 2 years ago * [Raycast](https://developers.raycast.com/information/security#raycast) * [Publishing Process](https://developers.raycast.com/information/security#publishing-process) * [Runtime Model](https://developers.raycast.com/information/security#runtime-model) * [Permissions](https://developers.raycast.com/information/security#permissions) * [Data Storage](https://developers.raycast.com/information/security#data-storage) * [Automatic Updates](https://developers.raycast.com/information/security#automatic-updates) --- # Best Practices | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/best-practices.md) . [](https://developers.raycast.com/information/best-practices#general) General ---------------------------------------------------------------------------------- ### [](https://developers.raycast.com/information/best-practices#handle-errors) Handle errors Network requests can fail, permissions to files can be missing… More generally, errors happen. By default, we handle every unhandled exception or unresolved Promise and show error screens. However, you should handle the "expected" error cases for your command. You should aim not to disrupt the user's flow just because something went wrong. For example, if a network request fails but you can read the cache, show the cache. A user might not need the fresh data straight away. In most cases, it's best to show a `Toast` with information about the error. Here is an example of how to show a toast for an error: Copy import { Detail, showToast, Toast } from "@raycast/api"; import { useEffect, useState } from "react"; export default function Command() { const [error, setError] = useState(); useEffect(() => { setTimeout(() => { setError(new Error("Booom πŸ’₯")); }, 1000); }, []); useEffect(() => { if (error) { showToast({ style: Toast.Style.Failure, title: "Something went wrong", message: error.message, }); } }, [error]); return ; } ### [](https://developers.raycast.com/information/best-practices#handle-runtime-dependencies) Handle runtime dependencies Ideally, your extension doesn't depend on any runtime dependencies. In reality, sometimes locally installed apps or CLIs are required to perform functionality. Here are a few tips to guarantee a good user experience: * If a command requires a runtime dependency to run (e.g. an app that needs to be installed by the user), show a helpful message. * If your extension is tightly coupled to an app, f.e. searching tabs in Safari or using AppleScript to control Spotify, checks don't always have to be strict because users most likely don't install the extension without having the dependency installed locally. * If only some functionality of your extension requires the runtime dependency, consider making this functionality only available if the dependency is installed. Typically, this is the best case for [actions](https://developers.raycast.com/information/terminology#action) , e.g. to open a URL in the desktop app instead of the browser. ### [](https://developers.raycast.com/information/best-practices#show-loading-indicator) Show loading indicator When commands need to load big data sets, it's best to inform the user about this. To keep your command snappy, it's important to render a React component as quickly as possible. You can start with an empty list or a static form and then load the data to fill the view. To make the user aware of the loading process, you can use the `isLoading` prop on all top-level components, e.g. [``](https://developers.raycast.com/api-reference/user-interface/detail) , [`
`](https://developers.raycast.com/api-reference/user-interface/form) , [``](https://developers.raycast.com/api-reference/user-interface/grid) , or [``](https://developers.raycast.com/api-reference/user-interface/list) . Here is an example to show the loading indicator in a list: * * * [](https://developers.raycast.com/information/best-practices#forms) Forms ------------------------------------------------------------------------------ ### [](https://developers.raycast.com/information/best-practices#use-forms-validation) Use Forms Validation Before submitting data, it is important to ensure all required form controls are filled out, in the correct format. In Raycast, validation can be fully controlled from the API. To keep the same behavior as we have natively, the proper way of usage is to validate a `value` in the `onBlur` callback, update the `error` of the item and keep track of updates with the `onChange` callback to drop the `error` value. The [useForm](https://developers.raycast.com/utilities/react-hooks/useform) utils hook nicely wraps this behavior and is the recommended way to do deal with validations. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-06326f9b2b6de5d39b9c8aa37e677b23c122f26e%252Fform-validation.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=2f1fd01f&sv=2) Keep in mind that if the Form has any errors, the [`Action.SubmitForm`](https://developers.raycast.com/api-reference/user-interface/actions#action.submitform) `onSubmit` callback won't be triggered. FormValidationWithUtils.tsx FormValidationWithoutUtils.tsx [PreviousDeeplinks](https://developers.raycast.com/information/lifecycle/deeplinks) [NextDeveloper Tools](https://developers.raycast.com/information/developer-tools) Last updated 6 months ago * [General](https://developers.raycast.com/information/best-practices#general) * [Handle errors](https://developers.raycast.com/information/best-practices#handle-errors) * [Handle runtime dependencies](https://developers.raycast.com/information/best-practices#handle-runtime-dependencies) * [Show loading indicator](https://developers.raycast.com/information/best-practices#show-loading-indicator) * [Forms](https://developers.raycast.com/information/best-practices#forms) * [Use Forms Validation](https://developers.raycast.com/information/best-practices#use-forms-validation) Copy import { List } from "@raycast/api"; import { useEffect, useState } from "react"; export default function Command() { const [items, setItems] = useState(); useEffect(() => { setTimeout(() => { setItems(["Item 1", "Item 2", "Item 3"]); }, 1000); }, []); return ( {items?.map((item, index) => ( ))} ); } Copy import { Action, ActionPanel, Form, showToast, Toast } from "@raycast/api"; import { useForm, FormValidation } from "@raycast/utils"; interface SignUpFormValues { name: string; password: string; } export default function Command() { const { handleSubmit, itemProps } = useForm({ onSubmit(values) { showToast({ style: Toast.Style.Success, title: "Yay!", message: `${values.name} account created`, }); }, validation: { name: FormValidation.Required, password: (value) => { if (value && value.length < 8) { return "Password must be at least 8 symbols"; } else if (!value) { return "The item is required"; } }, }, }); return ( } > ); } Copy import { Form } from "@raycast/api"; import { useState } from "react"; export default function Command() { const [nameError, setNameError] = useState(); const [passwordError, setPasswordError] = useState(); function dropNameErrorIfNeeded() { if (nameError && nameError.length > 0) { setNameError(undefined); } } function dropPasswordErrorIfNeeded() { if (passwordError && passwordError.length > 0) { setPasswordError(undefined); } } return (
{ if (event.target.value?.length == 0) { setNameError("The field should't be empty!"); } else { dropNameErrorIfNeeded(); } }} /> { const value = event.target.value; if (value && value.length > 0) { if (!validatePassword(value)) { setPasswordError("Password should be at least 8 characters!"); } else { dropPasswordErrorIfNeeded(); } } else { setPasswordError("The field should't be empty!"); } }} /> ); } function validatePassword(value: string): boolean { return value.length >= 8; } --- # Tool | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/tool.md) . Tools are a type of entry point for an extension. As opposed to a [command](https://developers.raycast.com/information/terminology#command) , they don’t show up in the root search and the user can’t directly interact with them. Instead, they are functionalities that the AI can use to interact with an extension. [](https://developers.raycast.com/api-reference/tool#types) Types ---------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/tool#tool.confirmation) Tool.Confirmation A tool confirmation is used to ask the user to validate the side-effects of the tool. The tool confirmation is executed _before_ the actual tool is executed and receives the same input as the tool. A confirmation returns an optional object that describes what the tool is about to do. It is important to be as clear as possible. If the user confirms the action, the tool will be executed afterwards. If the user cancels the action, the tool will not be executed. Copy type Confirmation = (input: T) => Promise< | undefined | { /** * Defines the visual style of the Confirmation. * * @remarks * Use {@link Action.Style.Regular} to display a regular action. * Use {@link Action.Style.Destructive} when your action performs something irreversible like deleting data. * * @defaultValue {@link Action.Style.Regular} */ style?: Action.Style; /** * Some name/value pairs that represents the side-effects of the tool. * * @remarks * Use it to provide more context about the tool to the user. For example, list the files that will be deleted. * * A name/value pair with an optional value won't be displayed if the value is `undefined`. */ info?: { name: string; value?: string; }[]; /** * A string that represents the side-effects of the tool. * * @remarks * Often times this is a question that the user needs to answer. For Example, "Are you sure you want to delete the file?" */ message?: string; /** * An image that visually represents the side-effects of the tool. * * @remarks * Use an image that is relevant to the side-effects of the tool. For example, a screenshot of the files that will be deleted. */ image?: Image.URL | FileIcon; } >; You can return `undefined` to skip the confirmation. This is useful for tools that conditionally perform destructive actions. F.e. when moving a file, you don't need to confirm the action if the file doesn't overwrite another file. #### [](https://developers.raycast.com/api-reference/tool#example) Example [PreviousRaycast Window & Search Bar](https://developers.raycast.com/api-reference/window-and-search-bar) [NextWindow Management](https://developers.raycast.com/api-reference/window-management) Last updated 1 year ago * [Types](https://developers.raycast.com/api-reference/tool#types) * [Tool.Confirmation](https://developers.raycast.com/api-reference/tool#tool.confirmation) Copy import { Tool } from "@raycast/api"; type Input = { /** * The first name of the user to greet */ name: string; }; export const confirmation: Tool.Confirmation = (input) => { return { message: `Are you sure you want to greet ${input.name}?`, }; }; --- # VS Code (community tool) | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/developer-tools/vscode.md) . You can enhance your VS Code development experience by installing the [Raycast extension in the marketplace](https://marketplace.visualstudio.com/items?itemName=tonka3000.raycast) . Here's a list of features provided by the extension: * IntelliSense for image assets * A tree view for easier navigation (commands and preferences) * VS Code commands for creating new commands and preferences * The possibility to attach a Node.js debugger * VS Code commands for `ray` operations like `build`, `dev`, `lint`, or `fix-lint` [PreviousForked Extensions (community tool)](https://developers.raycast.com/information/developer-tools/forked-extensions) [NextTemplates](https://developers.raycast.com/information/developer-tools/templates) Last updated 1 year ago --- # Browser Extension | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/browser-extension.md) . The Browser Extension API provides developers with deeper integration into the user's Browser _via_ a [Browser Extension](https://raycast.com/browser-extension) . Some users might not have installed the Browser Extension. If a user doesn't have the Browser Extension installed, they will be asked if they want to install it when your extension calls the Browser Extension API. If the user doesn't wish to install it, the API call will throw an error. You can check if a user has the Browser Extension installed using [`environment.canAccess(BrowserExtension)`](https://developers.raycast.com/api-reference/environment) . The API is not accessible on Windows for now. [](https://developers.raycast.com/api-reference/browser-extension#api-reference) API Reference --------------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/browser-extension#browserextension.getcontent) BrowserExtension.getContent Get the content of an opened browser tab. #### [](https://developers.raycast.com/api-reference/browser-extension#signature) Signature Copy async function getContent(options?: { cssSelector?: string; tabId?: number; format?: "html" | "text" | "markdown"; }): Promise; #### [](https://developers.raycast.com/api-reference/browser-extension#example) Example Basic Usage CSS Selector Copy import { BrowserExtension, Clipboard } from "@raycast/api"; export default async function command() { const markdown = await BrowserExtension.getContent({ format: "markdown" }); await Clipboard.copy(markdown); } Copy import { BrowserExtension, Clipboard } from "@raycast/api"; export default async function command() { const title = await BrowserExtension.getContent({ format: "text", cssSelector: "title" }); await Clipboard.copy(title); } #### [](https://developers.raycast.com/api-reference/browser-extension#parameters) Parameters Name Description Type options Options to control which content to get. `Object` options.cssSelector Only returns the content of the element that matches the [CSS selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_selectors) . If the selector matches multiple elements, only the first one is returned. If the selector doesn't match any element, an empty string is returned. When using a CSS selector, the `format` option can not be `markdown`. `string` options.format The format of the content. - `html`: `document.documentElement.outerHTML` - `text`: `document.body.innerText` - `markdown`: A heuristic to get the "content" of the document and convert it to markdown. Think of it as the "reader mode" of a browser. `"html"` or `"text"` or `"markdown"` options.tabId The ID of the tab to get the content from. If not specified, the content of the active tab of the focused window is returned. `number` #### [](https://developers.raycast.com/api-reference/browser-extension#return) Return A Promise that resolves with the content of the tab. ### [](https://developers.raycast.com/api-reference/browser-extension#browserextension.gettabs) BrowserExtension.getTabs Get the list of open browser tabs. #### [](https://developers.raycast.com/api-reference/browser-extension#signature-1) Signature #### [](https://developers.raycast.com/api-reference/browser-extension#example-1) Example #### [](https://developers.raycast.com/api-reference/browser-extension#return-1) Return A Promise that resolves with the list of [tabs](https://developers.raycast.com/api-reference/browser-extension#browserextension.tab) . [](https://developers.raycast.com/api-reference/browser-extension#types) Types ----------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/browser-extension#browserextension.tab) BrowserExtension.Tab #### [](https://developers.raycast.com/api-reference/browser-extension#properties) Properties Property Description Type active\* Whether the tab is active in its window. There can only be one active tab per window but if there are multiple browser windows, there can be multiple active tabs. `boolean` id\* The ID of the tab. Tab IDs are unique within a browser session. `number` url\* The URL the tab is displaying. `string` favicon The URL of the tab's [favicon](https://developer.mozilla.org/en-US/docs/Glossary/Favicon) . It may also be `undefined` if the tab is loading. `string` title The title of the tab. It may also be `undefined` if the tab is loading. `string` [PreviousAI](https://developers.raycast.com/api-reference/ai) [NextCache](https://developers.raycast.com/api-reference/cache) Last updated 10 months ago * [API Reference](https://developers.raycast.com/api-reference/browser-extension#api-reference) * [BrowserExtension.getContent](https://developers.raycast.com/api-reference/browser-extension#browserextension.getcontent) * [BrowserExtension.getTabs](https://developers.raycast.com/api-reference/browser-extension#browserextension.gettabs) * [Types](https://developers.raycast.com/api-reference/browser-extension#types) * [BrowserExtension.Tab](https://developers.raycast.com/api-reference/browser-extension#browserextension.tab) Copy async function getTabs(): Promise; Copy import { BrowserExtension } from "@raycast/api"; export default async function command() { const tabs = await BrowserExtension.getTabs(); console.log(tabs); } --- # Developer Tools | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/developer-tools.md) . Raycast provides several tools to smoothen your experience when building extensions: * [Manage Extensions Command](https://developers.raycast.com/information/developer-tools/manage-extensions-command) _\- A Raycast command to manage your extensions, add new command, etc._ * [CLI](https://developers.raycast.com/information/developer-tools/cli) _\- A CLI to build, develop, and lint your extension_ * [ESLint](https://developers.raycast.com/information/developer-tools/eslint) _\- An ESLint configuration helping you follow best practices as you build your extension_ * [Forked Extensions (community tool)](https://developers.raycast.com/information/developer-tools/forked-extensions) - _The extension for helping you manage your forked Raycast extensions_ * [VS Code (community tool)](https://developers.raycast.com/information/developer-tools/vscode) _\- A VS Code extension to enhance your development experience_ [PreviousBest Practices](https://developers.raycast.com/information/best-practices) [NextManage Extensions Command](https://developers.raycast.com/information/developer-tools/manage-extensions-command) Last updated 10 months ago --- # Preferences | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/preferences.md) . Use the Preferences API to make your extension configurable. Preferences are configured in the [manifest](https://developers.raycast.com/information/manifest#preference-properties) per command or shared in the context of an extension. Required preferences need to be set by the user before a command opens. They are a great way to make sure that the user of your extension has everything set up properly. [](https://developers.raycast.com/api-reference/preferences#api-reference) API Reference --------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/preferences#getpreferencevalues) getPreferenceValues A function to access the preference values that have been passed to the command. Each preference name is mapped to its value, and the defined default values are used as fallback values. #### [](https://developers.raycast.com/api-reference/preferences#signature) Signature Copy function getPreferenceValues(): { [preferenceName: string]: any }; You don't need to manually set preference types as an interface since it is autogenerated in `raycast-env.d.ts` when you run the extension. #### [](https://developers.raycast.com/api-reference/preferences#example) Example Copy import { getPreferenceValues } from "@raycast/api"; export default async function Command() { const preferences = getPreferenceValues(); console.log(preferences); } #### [](https://developers.raycast.com/api-reference/preferences#return) Return An object with the preference names as property key and the typed value as property value. Depending on the type of the preference, the type of its value will be different. Preference type Value type `textfield` `string` `password` `string` `checkbox` `boolean` `dropdown` `string` `appPicker` [`Application`](https://developers.raycast.com/api-reference/utilities#application) `file` `string` `directory` `string` ### [](https://developers.raycast.com/api-reference/preferences#openextensionpreferences) openExtensionPreferences Opens the extension's preferences screen. #### [](https://developers.raycast.com/api-reference/preferences#signature-1) Signature #### [](https://developers.raycast.com/api-reference/preferences#example-1) Example #### [](https://developers.raycast.com/api-reference/preferences#return-1) Return A Promise that resolves when the extensions preferences screen is opened. ### [](https://developers.raycast.com/api-reference/preferences#opencommandpreferences) openCommandPreferences Opens the command's preferences screen. #### [](https://developers.raycast.com/api-reference/preferences#signature-2) Signature #### [](https://developers.raycast.com/api-reference/preferences#example-2) Example #### [](https://developers.raycast.com/api-reference/preferences#return-2) Return A Promise that resolves when the command's preferences screen is opened. [](https://developers.raycast.com/api-reference/preferences#types) Types ----------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/preferences#preferences) Preferences A command receives the values of its preferences via the [`getPreferenceValues`](https://developers.raycast.com/api-reference/preferences#getpreferencevalues) function. It is an object with the preferences' `name` as keys and their values as the property's values. Depending on the type of the preference, the type of its value will be different. Preference type Value type `textfield` `string` `password` `string` `checkbox` `boolean` `dropdown` `string` `appPicker` [`Application`](https://developers.raycast.com/api-reference/utilities#application) `file` `string` `directory` `string` Raycast provides a global TypeScript namespace called `Preferences` which contains the types of the preferences of all the commands of the extension. For example, if a command named `show-todos` has some preferences, its `getPreferenceValues`'s return type can be specified with `getPreferenceValues()`. This will make sure that the types used in the command stay in sync with the manifest. [PreviousOAuth](https://developers.raycast.com/api-reference/oauth) [NextStorage](https://developers.raycast.com/api-reference/storage) Last updated 11 months ago * [API Reference](https://developers.raycast.com/api-reference/preferences#api-reference) * [getPreferenceValues](https://developers.raycast.com/api-reference/preferences#getpreferencevalues) * [openExtensionPreferences](https://developers.raycast.com/api-reference/preferences#openextensionpreferences) * [openCommandPreferences](https://developers.raycast.com/api-reference/preferences#opencommandpreferences) * [Types](https://developers.raycast.com/api-reference/preferences#types) * [Preferences](https://developers.raycast.com/api-reference/preferences#preferences) Copy export declare function openExtensionPreferences(): Promise; Copy import { ActionPanel, Action, Detail, openExtensionPreferences } from "@raycast/api"; export default function Command() { const markdown = "API key incorrect. Please update it in extension preferences and try again."; return ( } /> ); } Copy export declare function openCommandPreferences(): Promise; Copy import { ActionPanel, Action, Detail, openCommandPreferences } from "@raycast/api"; export default function Command() { const markdown = "API key incorrect. Please update it in command preferences and try again."; return ( } /> ); } --- # Forked Extensions (community tool) | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/developer-tools/forked-extensions.md) . This extension leverages the [Git sparse-checkout](https://git-scm.com/docs/git-sparse-checkout) feature to efficiently manage your forked extensions. Our goal is to eliminate the need for cloning the entire repository, which can exceed 20 GB in size, by enabling sparse-checkout. With this extension, you can forgo Ray CLI's commands, allowing you to use Git commands directly and regular [GitHub flow](https://docs.github.com/en/get-started/using-github/github-flow) for managing your extensions. [](https://developers.raycast.com/information/developer-tools/forked-extensions#features) Features ------------------------------------------------------------------------------------------------------- * Explore full extension list * Only fork the extension you need to save space * Remove an extension from forked list * Synchronize the forked repository with the upstream repository on local [](https://developers.raycast.com/information/developer-tools/forked-extensions#install) Install ----------------------------------------------------------------------------------------------------- The extension is available on the [Raycast Store](https://www.raycast.com/litomore/forked-extensions) . [![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2Fwww.raycast.com%2Flitomore%2Fforked-extensions%2Finstall_button%402x.png%3Fv%3D1.1&width=300&dpr=3&quality=100&sign=8de94fa3&sv=2)](https://www.raycast.com/litomore/forked-extensions) [](https://developers.raycast.com/information/developer-tools/forked-extensions#hint) Hint ----------------------------------------------------------------------------------------------- Please note with this extension you no longer need to use Ray CLI's `pull-contributions` and `publish` commands. Just use Git commands or your favorite Git GUI tool to manage your forked extensions. [PreviousESLint](https://developers.raycast.com/information/developer-tools/eslint) [NextVS Code (community tool)](https://developers.raycast.com/information/developer-tools/vscode) Last updated 6 months ago * [Features](https://developers.raycast.com/information/developer-tools/forked-extensions#features) * [Install](https://developers.raycast.com/information/developer-tools/forked-extensions#install) * [Hint](https://developers.raycast.com/information/developer-tools/forked-extensions#hint) --- # HUD | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/feedback/hud.md) . When the user takes an action that has the side effect of closing Raycast (for example when copying something in the [Clipboard](https://developers.raycast.com/api-reference/clipboard) ), you can use a HUD to confirm that the action worked properly. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-690446648e9c7bb76403f9d177ecfc8a3851ee8a%252Fhud.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=874d03a0&sv=2) [](https://developers.raycast.com/api-reference/feedback/hud#api-reference) API Reference ---------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/feedback/hud#showhud) showHUD A HUD will automatically hide the main window and show a compact message at the bottom of the screen. #### [](https://developers.raycast.com/api-reference/feedback/hud#signature) Signature #### [](https://developers.raycast.com/api-reference/feedback/hud#example) Example `showHUD` closes the main window when called, so you can use the same options as `closeMainWindow`: #### [](https://developers.raycast.com/api-reference/feedback/hud#parameters) Parameters Name Description Type title\* The title that will be displayed in the HUD. `string` options Can be used to control the behaviour after closing the main window. `Object` options.clearRootSearch Clears the text in the root search bar and scrolls to the top `boolean` options.popToRootType Defines the pop to root behavior (PopToRootType); the default is to to respect the user's "Pop to Root Search" preference in Raycast [`PopToRootType`](https://developers.raycast.com/api-reference/window-and-search-bar#poptoroottype) #### [](https://developers.raycast.com/api-reference/feedback/hud#return) Return A Promise that resolves when the HUD is shown. [PreviousAlert](https://developers.raycast.com/api-reference/feedback/alert) [NextToast](https://developers.raycast.com/api-reference/feedback/toast) Last updated 1 year ago * [API Reference](https://developers.raycast.com/api-reference/feedback/hud#api-reference) * [showHUD](https://developers.raycast.com/api-reference/feedback/hud#showhud) Copy async function showHUD( title: string, options?: { clearRootSearch?: boolean; popToRootType?: PopToRootType } ): Promise; Copy import { showHUD } from "@raycast/api"; export default async function Command() { await showHUD("Hey there πŸ‘‹"); } Copy import { PopToRootType, showHUD } from "@raycast/api"; export default async function Command() { await showHUD("Hey there πŸ‘‹", { clearRootSearch: true, popToRootType: PopToRootType.Immediate }); } --- # Command | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/command.md) . This set of utilities to work with Raycast commands. [](https://developers.raycast.com/api-reference/command#api-reference) API Reference ----------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/command#launchcommand) launchCommand Launches another command. If the command does not exist, or if it's not enabled, an error will be thrown. If the command is part of another extension, the user will be presented with a permission alert. Use this method if your command needs to open another command based on user interaction, or when an immediate background refresh should be triggered, for example when a command needs to update an associated menu-bar command. #### [](https://developers.raycast.com/api-reference/command#signature) Signature Copy export async function launchCommand(options: LaunchOptions): Promise; #### [](https://developers.raycast.com/api-reference/command#example) Example Copy import { launchCommand, LaunchType } from "@raycast/api"; export default async function Command() { await launchCommand({ name: "list", type: LaunchType.UserInitiated, context: { foo: "bar" } }); } #### [](https://developers.raycast.com/api-reference/command#parameters) Parameters Name Description Type options\* Options to launch a command within the same extension or in another extension. [`LaunchOptions`](https://developers.raycast.com/api-reference/command#launchoptions) #### [](https://developers.raycast.com/api-reference/command#return) Return A Promise that resolves when the command has been launched. (Note that this does not indicate that the launched command has finished executing.) ### [](https://developers.raycast.com/api-reference/command#updatecommandmetadata) updateCommandMetadata Update the values of properties declared in the manifest of the current command. Note that currently only `subtitle` is supported. Pass `null` to clear the custom subtitle. The actual manifest file is not modified, so the update applies as long as the command remains installed. #### [](https://developers.raycast.com/api-reference/command#signature-1) Signature #### [](https://developers.raycast.com/api-reference/command#example-1) Example #### [](https://developers.raycast.com/api-reference/command#return-1) Return A Promise that resolves when the command's metadata have been updated. [](https://developers.raycast.com/api-reference/command#types) Types ------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/command#launchcontext) LaunchContext Represents the passed context object of programmatic command launches. ### [](https://developers.raycast.com/api-reference/command#launchoptions) LaunchOptions A parameter object used to decide which command should be launched and what data (arguments, context) it should receive. #### [](https://developers.raycast.com/api-reference/command#intraextensionlaunchoptions) IntraExtensionLaunchOptions The options that can be used when launching a command from the same extension. Property Description Type name\* Command name as defined in the extension's manifest `string` type\* LaunchType.UserInitiated or LaunchType.Background [`LaunchType`](https://developers.raycast.com/api-reference/environment#launchtype) arguments Optional object for the argument properties and values as defined in the extension's manifest, for example: `{ "argument1": "value1" }` [`Arguments`](https://developers.raycast.com/information/lifecycle/arguments#arguments) context Arbitrary object for custom data that should be passed to the command and accessible as LaunchProps; the object must be JSON serializable (Dates and Buffers supported) [`LaunchContext`](https://developers.raycast.com/api-reference/command#launchcontext) fallbackText Optional string to send as fallback text to the command `string` #### [](https://developers.raycast.com/api-reference/command#interextensionlaunchoptions) InterExtensionLaunchOptions The options that can be used when launching a command from a different extension. Property Description Type extensionName\* When launching command from a different extension, the extension name (as defined in the extension's manifest) is necessary `string` name\* Command name as defined in the extension's manifest `string` ownerOrAuthorName\* When launching command from a different extension, the owner or author (as defined in the extension's manifest) is necessary `string` type\* LaunchType.UserInitiated or LaunchType.Background [`LaunchType`](https://developers.raycast.com/api-reference/environment#launchtype) arguments Optional object for the argument properties and values as defined in the extension's manifest, for example: `{ "argument1": "value1" }` [`Arguments`](https://developers.raycast.com/information/lifecycle/arguments#arguments) context Arbitrary object for custom data that should be passed to the command and accessible as LaunchProps; the object must be JSON serializable (Dates and Buffers supported) [`LaunchContext`](https://developers.raycast.com/api-reference/command#launchcontext) fallbackText Optional string to send as fallback text to the command `string` [PreviousCache](https://developers.raycast.com/api-reference/cache) [NextClipboard](https://developers.raycast.com/api-reference/clipboard) Last updated 13 days ago * [API Reference](https://developers.raycast.com/api-reference/command#api-reference) * [launchCommand](https://developers.raycast.com/api-reference/command#launchcommand) * [updateCommandMetadata](https://developers.raycast.com/api-reference/command#updatecommandmetadata) * [Types](https://developers.raycast.com/api-reference/command#types) * [LaunchContext](https://developers.raycast.com/api-reference/command#launchcontext) * [LaunchOptions](https://developers.raycast.com/api-reference/command#launchoptions) Copy export async function updateCommandMetadata(metadata: { subtitle?: string | null }): Promise; Copy import { updateCommandMetadata } from "@raycast/api"; async function fetchUnreadNotificationCount() { return 10; } export default async function Command() { const count = await fetchUnreadNotificationCount(); await updateCommandMetadata({ subtitle: `Unread Notifications: ${count}` }); } --- # Alert | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/feedback/alert.md) . When the user takes an important action (for example when irreversibly deleting something), you can ask for confirmation by using `confirmAlert`. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-18a8eeb2446fdc8e95157b412aa2c84fd22ffbfa%252Falert.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=33f30aa&sv=2) [](https://developers.raycast.com/api-reference/feedback/alert#api-reference) API Reference ------------------------------------------------------------------------------------------------ ### [](https://developers.raycast.com/api-reference/feedback/alert#confirmalert) confirmAlert Creates and shows a confirmation Alert with the given [options](https://developers.raycast.com/api-reference/feedback/alert#alert.options) . #### [](https://developers.raycast.com/api-reference/feedback/alert#signature) Signature #### [](https://developers.raycast.com/api-reference/feedback/alert#example) Example #### [](https://developers.raycast.com/api-reference/feedback/alert#parameters) Parameters Name Description Type options\* The options used to create the Alert. [`Alert.Options`](https://developers.raycast.com/api-reference/feedback/alert#alert.options) #### [](https://developers.raycast.com/api-reference/feedback/alert#return) Return A Promise that resolves to a boolean when the user triggers one of the actions. It will be `true` for the primary Action, `false` for the dismiss Action. [](https://developers.raycast.com/api-reference/feedback/alert#types) Types -------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/feedback/alert#alert.options) Alert.Options The options to create an Alert. #### [](https://developers.raycast.com/api-reference/feedback/alert#example-1) Example #### [](https://developers.raycast.com/api-reference/feedback/alert#properties) Properties Property Description Type title\* The title of an alert. Displayed below the icon. `string` dismissAction The Action to dismiss the alert. There usually shouldn't be any side effects when the user takes this action. [`Alert.ActionOptions`](https://developers.raycast.com/api-reference/feedback/alert#alert.actionoptions) icon The icon of an alert to illustrate the action. Displayed on the top. [`Image.ImageLike`](https://developers.raycast.com/api-reference/user-interface/icons-and-images#image.imagelike) message An additional message for an Alert. Useful to show more information, e.g. a confirmation message for a destructive action. `string` primaryAction The primary Action the user can take. [`Alert.ActionOptions`](https://developers.raycast.com/api-reference/feedback/alert#alert.actionoptions) rememberUserChoice If set to true, the Alert will also display a `Do not show this message again` checkbox. When checked, the answer is persisted and directly returned to the extension the next time the alert should be shown, without the user actually seeing the alert. `boolean` ### [](https://developers.raycast.com/api-reference/feedback/alert#alert.actionoptions) Alert.ActionOptions The options to create an Alert Action. #### [](https://developers.raycast.com/api-reference/feedback/alert#properties-1) Properties Property Description Type title\* The title of the action. `string` onAction A callback called when the action is triggered. `() => void` style The style of the action. [`Alert.ActionStyle`](https://developers.raycast.com/api-reference/feedback/alert#alert.actionstyle) ### [](https://developers.raycast.com/api-reference/feedback/alert#alert.actionstyle) Alert.ActionStyle Defines the visual style of an Action of the Alert. Use [Alert.ActionStyle.Default](https://developers.raycast.com/api-reference/feedback/alert#alert.actionstyle) for confirmations of a positive action. Use [Alert.ActionStyle.Destructive](https://developers.raycast.com/api-reference/feedback/alert#alert.actionstyle) for confirmations of a destructive action (eg. deleting a file). #### [](https://developers.raycast.com/api-reference/feedback/alert#enumeration-members) Enumeration members Name Value Default ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-cf694515bf72da488eea228c3511ea5667cacfe2%252Falert-action-default.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=24d3fb56&sv=2) Destructive ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-3529cca2309b77669ede9d8cc0bdff210a9b6f00%252Falert-action-destructive.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=3a254f27&sv=2) Cancel ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-e73a37408b953e1a0d6f9751d5e8f001c0f2556f%252Falert-action-cancel.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=844fb872&sv=2) [PreviousFeedback](https://developers.raycast.com/api-reference/feedback) [NextHUD](https://developers.raycast.com/api-reference/feedback/hud) Last updated 1 year ago * [API Reference](https://developers.raycast.com/api-reference/feedback/alert#api-reference) * [confirmAlert](https://developers.raycast.com/api-reference/feedback/alert#confirmalert) * [Types](https://developers.raycast.com/api-reference/feedback/alert#types) * [Alert.Options](https://developers.raycast.com/api-reference/feedback/alert#alert.options) * [Alert.ActionOptions](https://developers.raycast.com/api-reference/feedback/alert#alert.actionoptions) * [Alert.ActionStyle](https://developers.raycast.com/api-reference/feedback/alert#alert.actionstyle) Copy async function confirmAlert(options: Alert.Options): Promise; Copy import { confirmAlert } from "@raycast/api"; export default async function Command() { if (await confirmAlert({ title: "Are you sure?" })) { console.log("confirmed"); // do something } else { console.log("canceled"); } } Copy import { Alert, confirmAlert } from "@raycast/api"; export default async function Command() { const options: Alert.Options = { title: "Finished cooking", message: "Delicious pasta for lunch", primaryAction: { title: "Do something", onAction: () => { // while you can register a handler for an action, it's more elegant // to use the `if (await confirmAlert(...)) { ... }` pattern console.log("The alert action has been triggered"); }, }, }; await confirmAlert(options); } --- # Raycast Window & Search Bar | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/window-and-search-bar.md) . [](https://developers.raycast.com/api-reference/window-and-search-bar#api-reference) API Reference ------------------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/window-and-search-bar#clearsearchbar) clearSearchBar Clear the text in the search bar. #### [](https://developers.raycast.com/api-reference/window-and-search-bar#signature) Signature Copy async function clearSearchBar(options?: { forceScrollToTop?: boolean }): Promise; #### [](https://developers.raycast.com/api-reference/window-and-search-bar#parameters) Parameters Name Description Type options Can be used to control the behaviour after the search bar is cleared. `Object` options.forceScrollToTop Can be used to force scrolling to the top. Defaults to scrolling to the top after the the search bar was cleared. `boolean` #### [](https://developers.raycast.com/api-reference/window-and-search-bar#return) Return A Promise that resolves when the search bar is cleared. ### [](https://developers.raycast.com/api-reference/window-and-search-bar#closemainwindow) closeMainWindow Closes the main Raycast window. #### [](https://developers.raycast.com/api-reference/window-and-search-bar#signature-1) Signature Copy async function closeMainWindow(options?: { clearRootSearch?: boolean; popToRootType?: PopToRootType }): Promise; #### [](https://developers.raycast.com/api-reference/window-and-search-bar#example) Example You can use the `popToRootType` parameter to temporarily prevent Raycast from applying the user's "Pop to Root Search" preference in Raycast; for example, when you need to interact with an external system utility and then allow the user to return back to the view command: #### [](https://developers.raycast.com/api-reference/window-and-search-bar#parameters-1) Parameters Name Description Type options Can be used to control the behaviour after closing the main window. `Object` options.clearRootSearch Clears the text in the root search bar and scrolls to the top `boolean` options.popToRootType Defines the pop to root behavior (PopToRootType); the default is to to respect the user's "Pop to Root Search" preference in Raycast [`PopToRootType`](https://developers.raycast.com/api-reference/window-and-search-bar#poptoroottype) #### [](https://developers.raycast.com/api-reference/window-and-search-bar#return-1) Return A Promise that resolves when the main window is closed. ### [](https://developers.raycast.com/api-reference/window-and-search-bar#poptoroot) popToRoot Pops the navigation stack back to root search. #### [](https://developers.raycast.com/api-reference/window-and-search-bar#signature-2) Signature #### [](https://developers.raycast.com/api-reference/window-and-search-bar#example-1) Example #### [](https://developers.raycast.com/api-reference/window-and-search-bar#parameters-2) Parameters Name Description Type options Can be used to control the behaviour after going back to the root search. `Object` options.clearSearchBar `boolean` #### [](https://developers.raycast.com/api-reference/window-and-search-bar#return-2) Return A Promise that resolves when Raycast popped to root. [](https://developers.raycast.com/api-reference/window-and-search-bar#types) Types --------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/window-and-search-bar#poptoroottype) PopToRootType Defines the pop to root behavior when the main window is closed. #### [](https://developers.raycast.com/api-reference/window-and-search-bar#enumeration-members) Enumeration members Name Description Default Respects the user's "Pop to Root Search" preference in Raycast Immediate Immediately pops back to root Suspended Prevents Raycast from popping back to root [PreviousNavigation](https://developers.raycast.com/api-reference/user-interface/navigation) [NextTool](https://developers.raycast.com/api-reference/tool) Last updated 1 year ago * [API Reference](https://developers.raycast.com/api-reference/window-and-search-bar#api-reference) * [clearSearchBar](https://developers.raycast.com/api-reference/window-and-search-bar#clearsearchbar) * [closeMainWindow](https://developers.raycast.com/api-reference/window-and-search-bar#closemainwindow) * [popToRoot](https://developers.raycast.com/api-reference/window-and-search-bar#poptoroot) * [Types](https://developers.raycast.com/api-reference/window-and-search-bar#types) * [PopToRootType](https://developers.raycast.com/api-reference/window-and-search-bar#poptoroottype) Copy import { closeMainWindow } from "@raycast/api"; import { setTimeout } from "timers/promises"; export default async function Command() { await setTimeout(1000); await closeMainWindow({ clearRootSearch: true }); } Copy import { closeMainWindow, PopToRootType } from "@raycast/api"; export default async () => { await closeMainWindow({ popToRootType: PopToRootType.Suspended }); }; Copy async function popToRoot(options?: { clearSearchBar?: boolean }): Promise; Copy import { Detail, popToRoot } from "@raycast/api"; import { useEffect } from "react"; import { setTimeout } from "timers"; export default function Command() { useEffect(() => { setTimeout(() => { popToRoot({ clearSearchBar: true }); }, 3000); }, []); return ; } --- # getAvatarIcon | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/icons/getavataricon.md) . Icon to represent an avatar when you don't have one. The generated avatar will be generated from the initials of the name and have a colorful but consistent background. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-3c6269820bd9ecb9d18550e31d2fff626deefdc5%252Futils-avatar-icon.png%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=78d046e5&sv=2) Avatar Icon example [](https://developers.raycast.com/utilities/icons/getavataricon#signature) Signature ----------------------------------------------------------------------------------------- * `name` is a string of the subject's name. * `options.background` is a hexadecimal representation of a color to be used as the background color. By default, the hook will pick a random but consistent (eg. the same name will the same color) color from a set handpicked to nicely match Raycast. * `options.gradient` is a boolean to choose whether the background should have a slight gradient or not. By default, it will. Returns an [Image.Asset](https://developers.raycast.com/api-reference/user-interface/icons-and-images) that can be used where Raycast expects them. [](https://developers.raycast.com/utilities/icons/getavataricon#example) Example ------------------------------------------------------------------------------------- [PreviousIcons](https://developers.raycast.com/utilities/icons) [NextgetFavicon](https://developers.raycast.com/utilities/icons/getfavicon) Last updated 1 year ago * [Signature](https://developers.raycast.com/utilities/icons/getavataricon#signature) * [Example](https://developers.raycast.com/utilities/icons/getavataricon#example) Copy function getAvatarIcon( name: string, options?: { background?: string; gradient?: boolean; }, ): Image.Asset; Copy import { List } from "@raycast/api"; import { getAvatarIcon } from "@raycast/utils"; export default function Command() { return ( ); } --- # Cache | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/cache.md) . Caching abstraction that stores data on disk and supports LRU (least recently used) access. Since extensions can only consume up to a max. heap memory size, the cache only maintains a lightweight index in memory and stores the actual data in separate files on disk in the extension's support directory. [](https://developers.raycast.com/api-reference/cache#api-reference) API Reference --------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/cache#cache) Cache The `Cache` class provides CRUD-style methods (get, set, remove) to update and retrieve data synchronously based on a key. The data must be a string and it is up to the client to decide which serialization format to use. A typical use case would be to use `JSON.stringify` and `JSON.parse`. By default, the cache is shared between the commands of an extension. Use [Cache.Options](https://developers.raycast.com/api-reference/cache#cache.options) to configure a `namespace` per command if needed (for example, set it to [`environment.commandName`](https://developers.raycast.com/api-reference/environment) ). #### [](https://developers.raycast.com/api-reference/cache#signature) Signature Copy constructor(options: Cache.Options): Cache #### [](https://developers.raycast.com/api-reference/cache#example) Example Copy import { List, Cache } from "@raycast/api"; type Item = { id: string; title: string }; const cache = new Cache(); cache.set("items", JSON.stringify([{ id: "1", title: "Item 1" }])); export default function Command() { const cached = cache.get("items"); const items: Item[] = cached ? JSON.parse(cached) : []; return ( {items.map((item) => ( ))} ); } #### [](https://developers.raycast.com/api-reference/cache#properties) Properties Property Description Type isEmpty\* Returns `true` if the cache is empty, `false` otherwise. `boolean` #### [](https://developers.raycast.com/api-reference/cache#methods) Methods Method [`get(key: string): string | undefined`](https://developers.raycast.com/api-reference/cache#cache-get) [`has(key: string): boolean`](https://developers.raycast.com/api-reference/cache#cache-has) [`set(key: string, data: string): void`](https://developers.raycast.com/api-reference/cache#cache-set) [`remove(key: string): boolean`](https://developers.raycast.com/api-reference/cache#cache-remove) [`clear(options = { notifySubscribers: true }): void`](https://developers.raycast.com/api-reference/cache#cache-clear) [`subscribe(subscriber: Cache.Subscriber): Cache.Subscription`](https://developers.raycast.com/api-reference/cache#cache-subscribe) ### [](https://developers.raycast.com/api-reference/cache#cache-get) Cache#get Returns the data for the given key. If there is no data for the key, `undefined` is returned. If you want to just check for the existence of a key, use [has](https://developers.raycast.com/api-reference/cache#cache-has) . #### [](https://developers.raycast.com/api-reference/cache#signature-1) Signature #### [](https://developers.raycast.com/api-reference/cache#parameters) Parameters Name Description Type key\* The key of the Cache entry. `string` ### [](https://developers.raycast.com/api-reference/cache#cache-has) Cache#has Returns `true` if data for the key exists, `false` otherwise. You can use this method to check for entries without affecting the LRU access. #### [](https://developers.raycast.com/api-reference/cache#signature-2) Signature #### [](https://developers.raycast.com/api-reference/cache#parameters-1) Parameters Name Description Type key\* The key of the Cache entry. `string` ### [](https://developers.raycast.com/api-reference/cache#cache-set) Cache#set Sets the data for the given key. If the data exceeds the configured `capacity`, the least recently used entries are removed. This also notifies registered subscribers (see [subscribe](https://developers.raycast.com/api-reference/cache#cache-subscribe) ). #### [](https://developers.raycast.com/api-reference/cache#signature-3) Signature #### [](https://developers.raycast.com/api-reference/cache#parameters-2) Parameters Name Description Type key\* The key of the Cache entry. `string` data\* The stringified data of the Cache entry. `string` ### [](https://developers.raycast.com/api-reference/cache#cache-remove) Cache#remove Removes the data for the given key. This also notifies registered subscribers (see [subscribe](https://developers.raycast.com/api-reference/cache#cache-subscribe) ). Returns `true` if data for the key was removed, `false` otherwise. #### [](https://developers.raycast.com/api-reference/cache#signature-4) Signature ### [](https://developers.raycast.com/api-reference/cache#cache-clear) Cache#clear Clears all stored data. This also notifies registered subscribers (see [subscribe](https://developers.raycast.com/api-reference/cache#cache-subscribe) ) unless the `notifySubscribers` option is set to `false`. #### [](https://developers.raycast.com/api-reference/cache#signature-5) Signature #### [](https://developers.raycast.com/api-reference/cache#parameters-3) Parameters Name Description Type options Options with a `notifySubscribers` property. The default is `true`; set to `false` to disable notification of subscribers. `object` ### [](https://developers.raycast.com/api-reference/cache#cache-subscribe) Cache#subscribe Registers a new subscriber that gets notified when cache data is set or removed. Returns a function that can be called to remove the subscriber. #### [](https://developers.raycast.com/api-reference/cache#signature-6) Signature #### [](https://developers.raycast.com/api-reference/cache#parameters-4) Parameters Name Description Type subscriber A function that is called when the Cache is updated. The function receives two values: the `key` of the Cache entry that was updated or `undefined` when the Cache is cleared, and the associated `data`. [`Cache.Subscriber`](https://developers.raycast.com/api-reference/cache#cache.subscriber) [](https://developers.raycast.com/api-reference/cache#types) Types ----------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/cache#cache.options) Cache.Options The options for creating a new Cache. #### [](https://developers.raycast.com/api-reference/cache#properties-1) Properties Property Description Type capacity The capacity in bytes. If the stored data exceeds the capacity, the least recently used data is removed. The default capacity is 10 MB. `number` namespace If set, the Cache will be namespaced via a subdirectory. This can be useful to separate the caches for individual commands of an extension. By default, the cache is shared between the commands of an extension. `string` ### [](https://developers.raycast.com/api-reference/cache#cache.subscriber) Cache.Subscriber Function type used as parameter for [subscribe](https://developers.raycast.com/api-reference/cache#cache-subscribe) . ### [](https://developers.raycast.com/api-reference/cache#cache.subscription) Cache.Subscription Function type returned from [subscribe](https://developers.raycast.com/api-reference/cache#cache-subscribe) . [PreviousBrowser Extension](https://developers.raycast.com/api-reference/browser-extension) [NextCommand](https://developers.raycast.com/api-reference/command) Last updated 1 year ago * [API Reference](https://developers.raycast.com/api-reference/cache#api-reference) * [Cache](https://developers.raycast.com/api-reference/cache#cache) * [Cache#get](https://developers.raycast.com/api-reference/cache#cache-get) * [Cache#has](https://developers.raycast.com/api-reference/cache#cache-has) * [Cache#set](https://developers.raycast.com/api-reference/cache#cache-set) * [Cache#remove](https://developers.raycast.com/api-reference/cache#cache-remove) * [Cache#clear](https://developers.raycast.com/api-reference/cache#cache-clear) * [Cache#subscribe](https://developers.raycast.com/api-reference/cache#cache-subscribe) * [Types](https://developers.raycast.com/api-reference/cache#types) * [Cache.Options](https://developers.raycast.com/api-reference/cache#cache.options) * [Cache.Subscriber](https://developers.raycast.com/api-reference/cache#cache.subscriber) * [Cache.Subscription](https://developers.raycast.com/api-reference/cache#cache.subscription) Copy get(key: string): string | undefined Copy has(key: string): boolean Copy set(key: string, data: string) Copy remove(key: string): boolean Copy clear((options = { notifySubscribers: true })); Copy subscribe(subscriber: Cache.Subscriber): Cache.Subscription Copy type Subscriber = (key: string | undefined, data: string | undefined) => void; Copy type Subscription = () => void; --- # Environment | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/environment.md) . The Environment APIs are useful to get context about the setup in which your command runs. You can get information about the extension and command itself as well as Raycast. Furthermore, a few paths are injected and are helpful to construct file paths that are related to the command's assets. [](https://developers.raycast.com/api-reference/environment#api-reference) API Reference --------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/environment#environment) environment Contains environment values such as the Raycast version, extension info, and paths. #### [](https://developers.raycast.com/api-reference/environment#example) Example Copy import { environment } from "@raycast/api"; export default async function Command() { console.log(`Raycast version: ${environment.raycastVersion}`); console.log(`Owner or Author name: ${environment.ownerOrAuthorName}`); console.log(`Extension name: ${environment.extensionName}`); console.log(`Command name: ${environment.commandName}`); console.log(`Command mode: ${environment.commandMode}`); console.log(`Assets path: ${environment.assetsPath}`); console.log(`Support path: ${environment.supportPath}`); console.log(`Is development mode: ${environment.isDevelopment}`); console.log(`Appearance: ${environment.appearance}`); console.log(`Text size: ${environment.textSize}`); console.log(`LaunchType: ${environment.launchType}`); } #### [](https://developers.raycast.com/api-reference/environment#properties) Properties Property Description Type appearance\* The appearance used by the Raycast application. `"dark"` or `"light"` assetsPath\* The absolute path to the assets directory of the extension. `string` commandMode\* The mode of the launched command, as specified in package.json `"view"` or `"no-view"` or `"menu-bar"` commandName\* The name of the launched command, as specified in package.json `string` extensionName\* The name of the extension, as specified in package.json `string` isDevelopment\* Indicates whether the command is a development command (vs. an installed command from the Store). `boolean` launchType\* The type of launch for the command (user initiated or background). [`LaunchType`](https://developers.raycast.com/api-reference/environment#launchtype) ownerOrAuthorName\* The name of the extension owner (if any) or author, as specified in package.json `string` raycastVersion\* The version of the main Raycast app `string` supportPath\* The absolute path for the support directory of an extension. Use it to read and write files related to your extension or command. `string` textSize\* The text size used by the Raycast application. `"medium"` or `"large"` canAccess\* `(api: unknown) => boolean` ### [](https://developers.raycast.com/api-reference/environment#environment.canaccess) environment.canAccess Checks whether the user can access a specific API or not. #### [](https://developers.raycast.com/api-reference/environment#signature) Signature #### [](https://developers.raycast.com/api-reference/environment#example-1) Example #### [](https://developers.raycast.com/api-reference/environment#return) Return A Boolean indicating whether the user running the command has access to the API. ### [](https://developers.raycast.com/api-reference/environment#getselectedfinderitems) getSelectedFinderItems Gets the selected items from Finder. #### [](https://developers.raycast.com/api-reference/environment#signature-1) Signature #### [](https://developers.raycast.com/api-reference/environment#example-2) Example #### [](https://developers.raycast.com/api-reference/environment#return-1) Return A Promise that resolves with the [selected file system items](https://developers.raycast.com/api-reference/environment#filesystemitem) . If Finder is not the frontmost application, the promise will be rejected. ### [](https://developers.raycast.com/api-reference/environment#getselectedtext) getSelectedText Gets the selected text of the frontmost application. #### [](https://developers.raycast.com/api-reference/environment#signature-2) Signature #### [](https://developers.raycast.com/api-reference/environment#example-3) Example #### [](https://developers.raycast.com/api-reference/environment#return-2) Return A Promise that resolves with the selected text. If no text is selected in the frontmost application, the promise will be rejected. [](https://developers.raycast.com/api-reference/environment#types) Types ----------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/environment#filesystemitem) FileSystemItem Holds data about a File System item. Use the [getSelectedFinderItems](https://developers.raycast.com/api-reference/environment#getselectedfinderitems) method to retrieve values. #### [](https://developers.raycast.com/api-reference/environment#properties-1) Properties Property Description Type path\* The path to the item `string` ### [](https://developers.raycast.com/api-reference/environment#launchtype) LaunchType Indicates the type of command launch. Use this to detect whether the command has been launched from the background. #### [](https://developers.raycast.com/api-reference/environment#enumeration-members) Enumeration members Name Description UserInitiated A regular launch through user interaction Background Scheduled through an interval and launched from background [PreviousClipboard](https://developers.raycast.com/api-reference/clipboard) [NextFeedback](https://developers.raycast.com/api-reference/feedback) Last updated 1 year ago * [API Reference](https://developers.raycast.com/api-reference/environment#api-reference) * [environment](https://developers.raycast.com/api-reference/environment#environment) * [environment.canAccess](https://developers.raycast.com/api-reference/environment#environment.canaccess) * [getSelectedFinderItems](https://developers.raycast.com/api-reference/environment#getselectedfinderitems) * [getSelectedText](https://developers.raycast.com/api-reference/environment#getselectedtext) * [Types](https://developers.raycast.com/api-reference/environment#types) * [FileSystemItem](https://developers.raycast.com/api-reference/environment#filesystemitem) * [LaunchType](https://developers.raycast.com/api-reference/environment#launchtype) Copy function canAccess(api: any): bool; Copy import { AI, showHUD, environment } from "@raycast/api"; import fs from "fs"; export default async function main() { if (environment.canAccess(AI)) { const answer = await AI.ask("Suggest 5 jazz songs"); await Clipboard.copy(answer); } else { await showHUD("You don't have access :("); } } Copy async function getSelectedFinderItems(): Promise; Copy import { getSelectedFinderItems, showToast, Toast } from "@raycast/api"; export default async function Command() { try { const selectedItems = await getSelectedFinderItems(); console.log(selectedItems); } catch (error) { await showToast({ style: Toast.Style.Failure, title: "Cannot copy file path", message: String(error), }); } } Copy async function getSelectedText(): Promise; Copy import { getSelectedText, Clipboard, showToast, Toast } from "@raycast/api"; export default async function Command() { try { const selectedText = await getSelectedText(); const transformedText = selectedText.toUpperCase(); await Clipboard.paste(transformedText); } catch (error) { await showToast({ style: Toast.Style.Failure, title: "Cannot transform text", message: String(error), }); } } --- # Clipboard | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/clipboard.md) . Use the Clipboard APIs to work with content from your clipboard. You can write contents to the clipboard through [`Clipboard.copy`](https://developers.raycast.com/api-reference/clipboard#clipboard.copy) and clear it through [`Clipboard.clear`](https://developers.raycast.com/api-reference/clipboard#clipboard.clear) . The [`Clipboard.paste`](https://developers.raycast.com/api-reference/clipboard#clipboard.paste) function inserts text at the current cursor position in your frontmost app. The action [`Action.CopyToClipboard`](https://developers.raycast.com/api-reference/user-interface/actions#action.copytoclipboard) can be used to copy content of a selected list item to the clipboard and the action [`Action.Paste`](https://developers.raycast.com/api-reference/user-interface/actions#action.paste) can be used to insert text in your frontmost app. [](https://developers.raycast.com/api-reference/clipboard#api-reference) API Reference ------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/clipboard#clipboard.copy) Clipboard.copy Copies text or a file to the clipboard. #### [](https://developers.raycast.com/api-reference/clipboard#signature) Signature Copy async function copy(content: string | number | Content, options?: CopyOptions): Promise; #### [](https://developers.raycast.com/api-reference/clipboard#example) Example Copy import { Clipboard } from "@raycast/api"; export default async function Command() { // copy some text await Clipboard.copy("https://raycast.com"); const textContent: Clipboard.Content = { text: "https://raycast.com", }; await Clipboard.copy(textContent); // copy a file const file = "/path/to/file.pdf"; try { const fileContent: Clipboard.Content = { file }; await Clipboard.copy(fileContent); } catch (error) { console.log(`Could not copy file '${file}'. Reason: ${error}`); } // copy confidential data await Clipboard.copy("my-secret-password", { concealed: true }); } #### [](https://developers.raycast.com/api-reference/clipboard#parameters) Parameters Name Description Type content\* The content to copy to the clipboard. `string` or `number` or [`Clipboard.Content`](https://developers.raycast.com/api-reference/clipboard#clipboard.content) options Options for the copy operation. [`Clipboard.CopyOptions`](https://developers.raycast.com/api-reference/clipboard#clipboard.copyoptions) #### [](https://developers.raycast.com/api-reference/clipboard#return) Return A Promise that resolves when the content is copied to the clipboard. ### [](https://developers.raycast.com/api-reference/clipboard#clipboard.paste) Clipboard.paste Pastes text or a file to the current selection of the frontmost application. #### [](https://developers.raycast.com/api-reference/clipboard#signature-1) Signature #### [](https://developers.raycast.com/api-reference/clipboard#example-1) Example #### [](https://developers.raycast.com/api-reference/clipboard#parameters-1) Parameters Name Description Type content\* The content to insert at the cursor. `string` or `number` or [`Clipboard.Content`](https://developers.raycast.com/api-reference/clipboard#clipboard.content) #### [](https://developers.raycast.com/api-reference/clipboard#return-1) Return A Promise that resolves when the content is pasted. ### [](https://developers.raycast.com/api-reference/clipboard#clipboard.clear) Clipboard.clear Clears the current clipboard contents. #### [](https://developers.raycast.com/api-reference/clipboard#signature-2) Signature #### [](https://developers.raycast.com/api-reference/clipboard#example-2) Example #### [](https://developers.raycast.com/api-reference/clipboard#return-2) Return A Promise that resolves when the clipboard is cleared. ### [](https://developers.raycast.com/api-reference/clipboard#clipboard.read) Clipboard.read Reads the clipboard content as plain text, file name, or HTML. #### [](https://developers.raycast.com/api-reference/clipboard#signature-3) Signature #### [](https://developers.raycast.com/api-reference/clipboard#example-3) Example #### [](https://developers.raycast.com/api-reference/clipboard#parameters-2) Parameters Name Description Type options Options for the read operation. `Object` options.offset Specify an offset to access the Clipboard History. Minimum value is 0, maximum value is 5. `number` #### [](https://developers.raycast.com/api-reference/clipboard#return-3) Return A promise that resolves when the clipboard content was read as plain text, file name, or HTML. ### [](https://developers.raycast.com/api-reference/clipboard#clipboard.readtext) Clipboard.readText Reads the clipboard as plain text. #### [](https://developers.raycast.com/api-reference/clipboard#signature-4) Signature #### [](https://developers.raycast.com/api-reference/clipboard#example-4) Example #### [](https://developers.raycast.com/api-reference/clipboard#parameters-3) Parameters Name Description Type options Options for the readText operation. `Object` options.offset Specify an offset to access the Clipboard History. Minimum value is 0, maximum value is 5. `number` #### [](https://developers.raycast.com/api-reference/clipboard#return-4) Return A promise that resolves once the clipboard content is read as plain text. [](https://developers.raycast.com/api-reference/clipboard#types) Types --------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/clipboard#clipboard.content) Clipboard.Content Type of content that is copied and pasted to and from the Clipboard ### [](https://developers.raycast.com/api-reference/clipboard#clipboard.readcontent) Clipboard.ReadContent Type of content that is read from the Clipboard ### [](https://developers.raycast.com/api-reference/clipboard#clipboard.copyoptions) Clipboard.CopyOptions Type of options passed to `Clipboard.copy`. #### [](https://developers.raycast.com/api-reference/clipboard#properties) Properties Property Description Type concealed Indicates whether the content be treated as confidential. If `true`, it will not be recorded in the Clipboard History. `boolean` [PreviousCommand](https://developers.raycast.com/api-reference/command) [NextEnvironment](https://developers.raycast.com/api-reference/environment) Last updated 1 year ago * [API Reference](https://developers.raycast.com/api-reference/clipboard#api-reference) * [Clipboard.copy](https://developers.raycast.com/api-reference/clipboard#clipboard.copy) * [Clipboard.paste](https://developers.raycast.com/api-reference/clipboard#clipboard.paste) * [Clipboard.clear](https://developers.raycast.com/api-reference/clipboard#clipboard.clear) * [Clipboard.read](https://developers.raycast.com/api-reference/clipboard#clipboard.read) * [Clipboard.readText](https://developers.raycast.com/api-reference/clipboard#clipboard.readtext) * [Types](https://developers.raycast.com/api-reference/clipboard#types) * [Clipboard.Content](https://developers.raycast.com/api-reference/clipboard#clipboard.content) * [Clipboard.ReadContent](https://developers.raycast.com/api-reference/clipboard#clipboard.readcontent) * [Clipboard.CopyOptions](https://developers.raycast.com/api-reference/clipboard#clipboard.copyoptions) Copy async function paste(content: string | Content): Promise; Copy import { Clipboard } from "@raycast/api"; export default async function Command() { await Clipboard.paste("I really like Raycast's API"); } Copy async function clear(): Promise; Copy import { Clipboard } from "@raycast/api"; export default async function Command() { await Clipboard.clear(); } Copy async function read(options?: { offset?: number }): Promise; Copy import { Clipboard } from "@raycast/api"; export default async () => { const { text, file, html } = await Clipboard.read(); console.log(text); console.log(file); console.log(html); }; Copy async function readText(options?: { offset?: number }): Promise; Copy import { Clipboard } from "@raycast/api"; export default async function Command() { const text = await Clipboard.readText(); console.log(text); } Copy type Content = | { text: string; } | { file: PathLike; } | { html: string; text?: string; // The alternative text representation of the content. }; Copy type Content = | { text: string; } | { file?: string; } | { html?: string; }; --- # Functions | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/functions.md) . [createDeeplink](https://developers.raycast.com/utilities/functions/createdeeplink) [executeSQL](https://developers.raycast.com/utilities/functions/executesql) [runAppleScript](https://developers.raycast.com/utilities/functions/runapplescript) [runPowerShellScript](https://developers.raycast.com/utilities/functions/runpowershellscript) [showFailureToast](https://developers.raycast.com/utilities/functions/showfailuretoast) [withCache](https://developers.raycast.com/utilities/functions/withcache) [PreviousGetting Started](https://developers.raycast.com/utilities/getting-started) [NextcreateDeeplink](https://developers.raycast.com/utilities/functions/createdeeplink) Last updated 2 years ago --- # Storage | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/storage.md) . The storage APIs can be used to store data in Raycast's [local encrypted database](https://developers.raycast.com/information/security#data-storage) . All commands in an extension have shared access to the stored data. Extensions can _not_ access the storage of other extensions. Values can be managed through functions such as [`LocalStorage.getItem`](https://developers.raycast.com/api-reference/storage#localstorage.getitem) , [`LocalStorage.setItem`](https://developers.raycast.com/api-reference/storage#localstorage.setitem) , or [`LocalStorage.removeItem`](https://developers.raycast.com/api-reference/storage#localstorage.removeitem) . A typical use case is storing user-related data, for example entered todos. The API is not meant to store large amounts of data. For this, use [Node's built-in APIs to write files](https://nodejs.org/en/learn/manipulating-files/writing-files-with-nodejs) , e.g. to the extension's [support directory](https://developers.raycast.com/api-reference/environment#environment) . [](https://developers.raycast.com/api-reference/storage#api-reference) API Reference ----------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/storage#localstorage.getitem) LocalStorage.getItem Retrieve the stored value for the given key. #### [](https://developers.raycast.com/api-reference/storage#signature) Signature Copy async function getItem(key: string): Promise; #### [](https://developers.raycast.com/api-reference/storage#example) Example Copy import { LocalStorage } from "@raycast/api"; export default async function Command() { await LocalStorage.setItem("favorite-fruit", "apple"); const item = await LocalStorage.getItem("favorite-fruit"); console.log(item); } #### [](https://developers.raycast.com/api-reference/storage#parameters) Parameters Name Description Type key\* The key you want to retrieve the value of. `string` #### [](https://developers.raycast.com/api-reference/storage#return) Return A Promise that resolves with the stored value for the given key. If the key does not exist, `undefined` is returned. ### [](https://developers.raycast.com/api-reference/storage#localstorage.setitem) LocalStorage.setItem Stores a value for the given key. #### [](https://developers.raycast.com/api-reference/storage#signature-1) Signature #### [](https://developers.raycast.com/api-reference/storage#example-1) Example #### [](https://developers.raycast.com/api-reference/storage#parameters-1) Parameters Name Description Type key\* The key you want to create or update the value of. `string` value\* The value you want to create or update for the given key. [`LocalStorage.Value`](https://developers.raycast.com/api-reference/storage#localstorage.value) #### [](https://developers.raycast.com/api-reference/storage#return-1) Return A Promise that resolves when the value is stored. ### [](https://developers.raycast.com/api-reference/storage#localstorage.removeitem) LocalStorage.removeItem Removes the stored value for the given key. #### [](https://developers.raycast.com/api-reference/storage#signature-2) Signature #### [](https://developers.raycast.com/api-reference/storage#example-2) Example #### [](https://developers.raycast.com/api-reference/storage#parameters-2) Parameters Name Description Type key\* The key you want to remove the value of. `string` #### [](https://developers.raycast.com/api-reference/storage#return-2) Return A Promise that resolves when the value is removed. ### [](https://developers.raycast.com/api-reference/storage#localstorage.allitems) LocalStorage.allItems Retrieve all stored values in the local storage of an extension. #### [](https://developers.raycast.com/api-reference/storage#signature-3) Signature #### [](https://developers.raycast.com/api-reference/storage#example-3) Example #### [](https://developers.raycast.com/api-reference/storage#return-3) Return A Promise that resolves with an object containing all [Values](https://developers.raycast.com/api-reference/storage#localstorage.values) . ### [](https://developers.raycast.com/api-reference/storage#localstorage.clear) LocalStorage.clear Removes all stored values of an extension. #### [](https://developers.raycast.com/api-reference/storage#signature-4) Signature #### [](https://developers.raycast.com/api-reference/storage#example-4) Example #### [](https://developers.raycast.com/api-reference/storage#return-4) Return A Promise that resolves when all values are removed. [](https://developers.raycast.com/api-reference/storage#types) Types ------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/storage#localstorage.values) LocalStorage.Values Values of local storage items. For type-safe values, you can define your own interface. Use the keys of the local storage items as the property names. #### [](https://developers.raycast.com/api-reference/storage#properties) Properties Name Type Description \[key: string\] `any` The local storage value of a given key. ### [](https://developers.raycast.com/api-reference/storage#localstorage.value) LocalStorage.Value Supported storage value types. #### [](https://developers.raycast.com/api-reference/storage#example-5) Example [PreviousPreferences](https://developers.raycast.com/api-reference/preferences) [NextSystem Utilities](https://developers.raycast.com/api-reference/utilities) Last updated 2 years ago * [API Reference](https://developers.raycast.com/api-reference/storage#api-reference) * [LocalStorage.getItem](https://developers.raycast.com/api-reference/storage#localstorage.getitem) * [LocalStorage.setItem](https://developers.raycast.com/api-reference/storage#localstorage.setitem) * [LocalStorage.removeItem](https://developers.raycast.com/api-reference/storage#localstorage.removeitem) * [LocalStorage.allItems](https://developers.raycast.com/api-reference/storage#localstorage.allitems) * [LocalStorage.clear](https://developers.raycast.com/api-reference/storage#localstorage.clear) * [Types](https://developers.raycast.com/api-reference/storage#types) * [LocalStorage.Values](https://developers.raycast.com/api-reference/storage#localstorage.values) * [LocalStorage.Value](https://developers.raycast.com/api-reference/storage#localstorage.value) Copy async function setItem(key: string, value: Value): Promise; Copy import { LocalStorage } from "@raycast/api"; export default async function Command() { await LocalStorage.setItem("favorite-fruit", "apple"); const item = await LocalStorage.getItem("favorite-fruit"); console.log(item); } Copy async function removeItem(key: string): Promise; Copy import { LocalStorage } from "@raycast/api"; export default async function Command() { await LocalStorage.setItem("favorite-fruit", "apple"); console.log(await LocalStorage.getItem("favorite-fruit")); await LocalStorage.removeItem("favorite-fruit"); console.log(await LocalStorage.getItem("favorite-fruit")); } Copy async function allItems(): Promise; Copy import { LocalStorage } from "@raycast/api"; interface Values { todo: string; priority: number; } export default async function Command() { const items = await LocalStorage.allItems(); console.log(`Local storage item count: ${Object.entries(items).length}`); } Copy async function clear(): Promise; Copy import { LocalStorage } from "@raycast/api"; export default async function Command() { await LocalStorage.clear(); } Copy Value: string | number | boolean; Copy import { LocalStorage } from "@raycast/api"; export default async function Command() { // String await LocalStorage.setItem("favorite-fruit", "cherry"); // Number await LocalStorage.setItem("fruit-basket-count", 3); // Boolean await LocalStorage.setItem("fruit-eaten-today", true); } --- # Feedback | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/feedback.md) . Raycast has several ways to provide feedback to the user: * [Toast](https://developers.raycast.com/api-reference/feedback/toast) _\- when an asynchronous operation is happening or when an error is thrown_ * [HUD](https://developers.raycast.com/api-reference/feedback/hud) _\- to confirm an action worked after closing Raycast_ * [Alert](https://developers.raycast.com/api-reference/feedback/alert) _\- to ask for confirmation before taking an action_ ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-607b51d1dc3e47c6cdff37be217a0e4d42368a57%252Ftoast.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=3dca9c04&sv=2) [PreviousEnvironment](https://developers.raycast.com/api-reference/environment) [NextAlert](https://developers.raycast.com/api-reference/feedback/alert) Last updated 1 year ago --- # Keyboard | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/keyboard.md) . The Keyboard APIs are useful to make your actions accessible via the keyboard shortcuts. Shortcuts help users to use your command without touching the mouse. Use the [Common shortcuts](https://developers.raycast.com/api-reference/keyboard#keyboard.shortcut.common) whenever possible to keep a consistent user experience throughout Raycast. [](https://developers.raycast.com/api-reference/keyboard#types) Types -------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/keyboard#keyboard.shortcut) Keyboard.Shortcut A keyboard shortcut is defined by one or more modifier keys (command, control, etc.) and a single key equivalent (a character or special key). See [KeyModifier](https://developers.raycast.com/api-reference/keyboard#keyboard.keymodifier) and [KeyEquivalent](https://developers.raycast.com/api-reference/keyboard#keyboard.keyequivalent) for supported values. #### [](https://developers.raycast.com/api-reference/keyboard#example) Example Copy import { Action, ActionPanel, Detail, Keyboard } from "@raycast/api"; export default function Command() { return ( console.log("Go up")} /> console.log("Go down")} /> console.log("Go left")} /> console.log("Go right")} /> console.log("Open")} /> } /> ); } #### [](https://developers.raycast.com/api-reference/keyboard#properties) Properties Property Description Type key\* The key of the keyboard shortcut. [`Keyboard.KeyEquivalent`](https://developers.raycast.com/api-reference/keyboard#keyboard.keyequivalent) modifiers\* The modifier keys of the keyboard shortcut. [`Keyboard.KeyModifier`](https://developers.raycast.com/api-reference/keyboard#keyboard.keymodifier) `[]` If the shortcut contains some "ambiguous" modifiers (eg. `ctrl`, or `cmd`, or `windows`), you will need to specify the shortcut for both platforms: ### [](https://developers.raycast.com/api-reference/keyboard#keyboard.shortcut.common) Keyboard.Shortcut.Common A collection of shortcuts that are commonly used throughout Raycast. Using them should help provide a more consistent experience and preserve muscle memory. Name macOS Windows Copy ⌘ + ⇧ + C `ctrl` + `shift` + C CopyDeeplink ⌘ + ⇧ + C `ctrl` + `shift` + C CopyName ⌘ + ⇧ + . `ctrl` + `alt` + C CopyPath ⌘ + ⇧ + , `alt` + `shift` + C Save ⌘ + S `ctrl` + S Duplicate ⌘ + D `ctrl` + `shift` + S Edit ⌘ + E `ctrl` + E MoveDown ⌘ + ⇧ + ↓ `ctrl` + `shift` + ↓ MoveUp ⌘ + ⇧ + ↑ `ctrl` + `shift` + ↑ New ⌘ + N `ctrl` + N Open ⌘ + O `ctrl` + O OpenWith ⌘ + ⇧ + O `ctrl` + `shift` + O Pin ⌘ + ⇧ + P `ctrl` + . Refresh ⌘ + R `ctrl` + R Remove βŒƒ + X `ctrl` + D RemoveAll βŒƒ + ⇧ + X `ctrl` + `shift` + D ToggleQuickLook ⌘ + Y `ctrl` + Y ### [](https://developers.raycast.com/api-reference/keyboard#keyboard.keyequivalent) Keyboard.KeyEquivalent KeyEquivalent of a [Shortcut](https://developers.raycast.com/api-reference/keyboard#keyboard.shortcut) ### [](https://developers.raycast.com/api-reference/keyboard#keyboard.keymodifier) Keyboard.KeyModifier Modifier of a [Shortcut](https://developers.raycast.com/api-reference/keyboard#keyboard.shortcut) . Note that `"alt"` and `"opt"` are the same key, they are just named differently on macOS and Windows. [PreviousToast](https://developers.raycast.com/api-reference/feedback/toast) [NextMenu Bar Commands](https://developers.raycast.com/api-reference/menu-bar-commands) Last updated 9 months ago * [Types](https://developers.raycast.com/api-reference/keyboard#types) * [Keyboard.Shortcut](https://developers.raycast.com/api-reference/keyboard#keyboard.shortcut) * [Keyboard.Shortcut.Common](https://developers.raycast.com/api-reference/keyboard#keyboard.shortcut.common) * [Keyboard.KeyEquivalent](https://developers.raycast.com/api-reference/keyboard#keyboard.keyequivalent) * [Keyboard.KeyModifier](https://developers.raycast.com/api-reference/keyboard#keyboard.keymodifier) Copy { macOS: { modifiers: ["cmd", "shift"], key: "c" }, Windows: { modifiers: ["ctrl", "shift"], key: "c" }, } Copy KeyEquivalent: "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "." | "," | ";" | "=" | "+" | "-" | "[" |\ "]" | "{" | "}" | "Β«" | "Β»" | "(" | ")" | "/" | "\\" | "'" | "`" | "Β§" | "^" | "@" | "$" | "return" | "delete" | "deleteForward" | "tab" | "arrowUp" | "arrowDown" | "arrowLeft" | "arrowRight" | "pageUp" | "pageDown" | "home" | "end" | "space" | "escape" | "enter" | "backspace"; Copy KeyModifier: "cmd" | "ctrl" | "opt" | "shift" | "alt" | "windows"; --- # runPowerShellScript | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/functions/runpowershellscript.md) . Function that executes an PowerShell script. Only available on Windows [](https://developers.raycast.com/utilities/functions/runpowershellscript#signature) Signature --------------------------------------------------------------------------------------------------- Copy function runPowerShellScript( script: string, options?: { signal?: AbortSignal; timeout?: number; parseOutput?: ParseExecOutputHandler; }, ): Promise; ### [](https://developers.raycast.com/utilities/functions/runpowershellscript#arguments) Arguments * `script` is the script to execute. With a few options: * `options.signal` is a Signal object that allows you to abort the request if required via an AbortController object. * `options.timeout` is a number. If greater than `0`, the parent will send the signal `SIGTERM` if the script runs longer than timeout milliseconds. By default, the execution will timeout after 10000ms (eg. 10s). * `options.parseOutput` is a function that accepts the output of the script as an argument and returns the data the hooks will return - see [ParseExecOutputHandler](https://developers.raycast.com/utilities/functions/runpowershellscript#parseexecoutputhandler) . By default, the function will return `stdout` as a string. ### [](https://developers.raycast.com/utilities/functions/runpowershellscript#return) Return Returns a Promise which resolves to a string by default. You can control what it returns by passing `options.parseOutput`. [](https://developers.raycast.com/utilities/functions/runpowershellscript#example) Example ----------------------------------------------------------------------------------------------- [](https://developers.raycast.com/utilities/functions/runpowershellscript#types) Types ------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/utilities/functions/runpowershellscript#parseexecoutputhandler) ParseExecOutputHandler A function that accepts the output of the script as an argument and returns the data the function will return. [PreviousrunAppleScript](https://developers.raycast.com/utilities/functions/runapplescript) [NextshowFailureToast](https://developers.raycast.com/utilities/functions/showfailuretoast) Last updated 9 months ago * [Signature](https://developers.raycast.com/utilities/functions/runpowershellscript#signature) * [Arguments](https://developers.raycast.com/utilities/functions/runpowershellscript#arguments) * [Return](https://developers.raycast.com/utilities/functions/runpowershellscript#return) * [Example](https://developers.raycast.com/utilities/functions/runpowershellscript#example) * [Types](https://developers.raycast.com/utilities/functions/runpowershellscript#types) * [ParseExecOutputHandler](https://developers.raycast.com/utilities/functions/runpowershellscript#parseexecoutputhandler) Copy import { showHUD } from "@raycast/api"; import { runPowerShellScript } from "@raycast/utils"; export default async function () { const res = await runPowerShellScript( ` Write-Host "hello, world." `, ); await showHUD(res); } Copy export type ParseExecOutputHandler = (args: { /** The output of the script on stdout. */ stdout: string; /** The output of the script on stderr. */ stderr: string; error?: Error | undefined; /** The numeric exit code of the process that was run. */ exitCode: number | null; /** The name of the signal that was used to terminate the process. For example, SIGFPE. */ signal: NodeJS.Signals | null; /** Whether the process timed out. */ timedOut: boolean; /** The command that was run, for logging purposes. */ command: string; /** The options passed to the script, for logging purposes. */ options?: ExecOptions | undefined; }) => T; --- # executeSQL | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/functions/executesql.md) . A function that executes a SQL query on a local SQLite database and returns the query result in JSON format. [](https://developers.raycast.com/utilities/functions/executesql#signature) Signature ------------------------------------------------------------------------------------------ Copy function executeSQL(databasePath: string, query: string): Promise ### [](https://developers.raycast.com/utilities/functions/executesql#arguments) Arguments * `databasePath` is the path to the local SQL database. * `query` is the SQL query to run on the database. ### [](https://developers.raycast.com/utilities/functions/executesql#return) Return Returns a `Promise` that resolves to an array of objects representing the query results. [](https://developers.raycast.com/utilities/functions/executesql#example) Example -------------------------------------------------------------------------------------- Copy import { closeMainWindow, Clipboard } from "@raycast/api"; import { executeSQL } from "@raycast/utils"; type Message = { body: string; code: string }; const DB_PATH = "/path/to/chat.db"; export default async function Command() { const query = ` SELECT body, code FROM message ORDER BY date DESC LIMIT 1; `; const messages = await executeSQL(DB_PATH, query); if (messages.length > 0) { const latestCode = messages[0].code; await Clipboard.paste(latestCode); await closeMainWindow(); } } [PreviouscreateDeeplink](https://developers.raycast.com/utilities/functions/createdeeplink) [NextrunAppleScript](https://developers.raycast.com/utilities/functions/runapplescript) Last updated 1 year ago * [Signature](https://developers.raycast.com/utilities/functions/executesql#signature) * [Arguments](https://developers.raycast.com/utilities/functions/executesql#arguments) * [Return](https://developers.raycast.com/utilities/functions/executesql#return) * [Example](https://developers.raycast.com/utilities/functions/executesql#example) --- # withCache | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/functions/withcache.md) . Higher-order function which wraps a function with caching functionality using Raycast's Cache API. Allows for caching of expensive functions like paginated API calls that rarely change. [](https://developers.raycast.com/utilities/functions/withcache#signature) Signature ----------------------------------------------------------------------------------------- Copy function withCache Promise>( fn: Fn, options?: { validate?: (data: Awaited>) => boolean; maxAge?: number; }, ): Fn & { clearCache: () => void }; ### [](https://developers.raycast.com/utilities/functions/withcache#arguments) Arguments `options` is an object containing: * `options.validate`: an optional function that receives the cached data and returns a boolean depending on whether the data is still valid or not. * `options.maxAge`: Maximum age of cached data in milliseconds after which the data will be considered invalid ### [](https://developers.raycast.com/utilities/functions/withcache#return) Return Returns the wrapped function [](https://developers.raycast.com/utilities/functions/withcache#example) Example ------------------------------------------------------------------------------------- [PreviousshowFailureToast](https://developers.raycast.com/utilities/functions/showfailuretoast) [NextIcons](https://developers.raycast.com/utilities/icons) Last updated 1 year ago * [Signature](https://developers.raycast.com/utilities/functions/withcache#signature) * [Arguments](https://developers.raycast.com/utilities/functions/withcache#arguments) * [Return](https://developers.raycast.com/utilities/functions/withcache#return) * [Example](https://developers.raycast.com/utilities/functions/withcache#example) Copy import { withCache } from "@raycast/utils"; function fetchExpensiveData(query) { // ... } const cachedFunction = withCache(fetchExpensiveData, { maxAge: 5 * 60 * 1000, // Cache for 5 minutes }); const result = await cachedFunction(query); --- # Toast | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/feedback/toast.md) . When an asynchronous operation is happening or when an error is thrown, it's usually a good idea to keep the user informed about it. Toasts are made for that. Additionally, Toasts can have some actions associated to the action they are about. For example, you could provide a way to cancel an asynchronous operation, undo an action, or copy the stack trace of an error. The `showToast()` will fallback to [showHUD()](https://developers.raycast.com/api-reference/feedback/hud#showhud) if the Raycast window is closed. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-607b51d1dc3e47c6cdff37be217a0e4d42368a57%252Ftoast.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=3dca9c04&sv=2) [](https://developers.raycast.com/api-reference/feedback/toast#api-reference) API Reference ------------------------------------------------------------------------------------------------ ### [](https://developers.raycast.com/api-reference/feedback/toast#showtoast) showToast Creates and shows a Toast with the given [options](https://developers.raycast.com/api-reference/feedback/toast#toast.options) . #### [](https://developers.raycast.com/api-reference/feedback/toast#signature) Signature #### [](https://developers.raycast.com/api-reference/feedback/toast#example) Example When showing an animated Toast, you can later on update it: #### [](https://developers.raycast.com/api-reference/feedback/toast#parameters) Parameters Name Description Type options\* The options to customize the Toast. [`Alert.Options`](https://developers.raycast.com/api-reference/feedback/alert#alert.options) #### [](https://developers.raycast.com/api-reference/feedback/toast#return) Return A Promise that resolves with the shown Toast. The Toast can be used to change or hide it. [](https://developers.raycast.com/api-reference/feedback/toast#types) Types -------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/feedback/toast#toast) Toast A Toast with a certain style, title, and message. Use [showToast](https://developers.raycast.com/api-reference/feedback/toast#showtoast) to create and show a Toast. #### [](https://developers.raycast.com/api-reference/feedback/toast#properties) Properties Property Description Type message An additional message for the Toast. Useful to show more information, e.g. an identifier of a newly created asset. `string` or `undefined` primaryAction The primary Action the user can take when hovering on the Toast. [`Alert.ActionOptions`](https://developers.raycast.com/api-reference/feedback/alert#alert.actionoptions) or `undefined` secondaryAction The secondary Action the user can take when hovering on the Toast. [`Alert.ActionOptions`](https://developers.raycast.com/api-reference/feedback/alert#alert.actionoptions) or `undefined` style The style of a Toast. [`Action.Style`](https://developers.raycast.com/api-reference/user-interface/actions#action.style) title The title of a Toast. Displayed on the top. `string` #### [](https://developers.raycast.com/api-reference/feedback/toast#methods) Methods Name Type Description hide `() => Promise` Hides the Toast. show `() => Promise` Shows the Toast. ### [](https://developers.raycast.com/api-reference/feedback/toast#toast.options) Toast.Options The options to create a [Toast](https://developers.raycast.com/api-reference/feedback/toast#toast) . #### [](https://developers.raycast.com/api-reference/feedback/toast#example-1) Example #### [](https://developers.raycast.com/api-reference/feedback/toast#properties-1) Properties Property Description Type title\* The title of a Toast. Displayed on the top. `string` message An additional message for the Toast. Useful to show more information, e.g. an identifier of a newly created asset. `string` primaryAction The primary Action the user can take when hovering on the Toast. [`Alert.ActionOptions`](https://developers.raycast.com/api-reference/feedback/alert#alert.actionoptions) secondaryAction The secondary Action the user can take when hovering on the Toast. [`Alert.ActionOptions`](https://developers.raycast.com/api-reference/feedback/alert#alert.actionoptions) style The style of a Toast. [`Action.Style`](https://developers.raycast.com/api-reference/user-interface/actions#action.style) ### [](https://developers.raycast.com/api-reference/feedback/toast#toast.style) Toast.Style Defines the visual style of the Toast. Use [Toast.Style.Success](https://developers.raycast.com/api-reference/feedback/toast#toast.style) for confirmations and [Toast.Style.Failure](https://developers.raycast.com/api-reference/feedback/toast#toast.style) for displaying errors. Use [Toast.Style.Animated](https://developers.raycast.com/api-reference/feedback/toast#toast.style) when your Toast should be shown until a process is completed. You can hide it later by using [Toast.hide](https://developers.raycast.com/api-reference/feedback/toast#toast) or update the properties of an existing Toast. #### [](https://developers.raycast.com/api-reference/feedback/toast#enumeration-members) Enumeration members Name Value Animated ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-7e62989ba2fea14db0967e09bb5bfaf84706e12d%252Ftoast-animated.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=b4078e38&sv=2) Success ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-dce0b170c3e47fa4c5525e1a0a74600350006445%252Ftoast-success.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=a02958ca&sv=2) Failure ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-96a3cfd7aaec6933c18481f6228bb647093217ff%252Ftoast-failure.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=76926ad2&sv=2) ### [](https://developers.raycast.com/api-reference/feedback/toast#toast.actionoptions) Toast.ActionOptions The options to create a [Toast](https://developers.raycast.com/api-reference/feedback/toast#toast) Action. #### [](https://developers.raycast.com/api-reference/feedback/toast#properties-2) Properties Property Description Type onAction\* A callback called when the action is triggered. `(toast:` [`Toast`](https://developers.raycast.com/api-reference/feedback/toast#toast) `) => void` title\* The title of the action. `string` shortcut The keyboard shortcut for the action. [`Keyboard.Shortcut`](https://developers.raycast.com/api-reference/keyboard#keyboard.shortcut) [PreviousHUD](https://developers.raycast.com/api-reference/feedback/hud) [NextKeyboard](https://developers.raycast.com/api-reference/keyboard) Last updated 13 days ago * [API Reference](https://developers.raycast.com/api-reference/feedback/toast#api-reference) * [showToast](https://developers.raycast.com/api-reference/feedback/toast#showtoast) * [Types](https://developers.raycast.com/api-reference/feedback/toast#types) * [Toast](https://developers.raycast.com/api-reference/feedback/toast#toast) * [Toast.Options](https://developers.raycast.com/api-reference/feedback/toast#toast.options) * [Toast.Style](https://developers.raycast.com/api-reference/feedback/toast#toast.style) * [Toast.ActionOptions](https://developers.raycast.com/api-reference/feedback/toast#toast.actionoptions) Copy async function showToast(options: Toast.Options): Promise; Copy import { showToast, Toast } from "@raycast/api"; export default async function Command() { const success = false; if (success) { await showToast({ title: "Dinner is ready", message: "Pizza margherita" }); } else { await showToast({ style: Toast.Style.Failure, title: "Dinner isn't ready", message: "Pizza dropped on the floor", }); } } Copy import { showToast, Toast } from "@raycast/api"; import { setTimeout } from "timers/promises"; export default async function Command() { const toast = await showToast({ style: Toast.Style.Animated, title: "Uploading image", }); try { // upload the image await setTimeout(1000); toast.style = Toast.Style.Success; toast.title = "Uploaded image"; } catch (err) { toast.style = Toast.Style.Failure; toast.title = "Failed to upload image"; if (err instanceof Error) { toast.message = err.message; } } } Copy import { showToast, Toast } from "@raycast/api"; export default async function Command() { const options: Toast.Options = { style: Toast.Style.Success, title: "Finished cooking", message: "Delicious pasta for lunch", primaryAction: { title: "Do something", onAction: (toast) => { console.log("The toast action has been triggered"); toast.hide(); }, }, }; await showToast(options); } --- # ESLint | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/developer-tools/eslint.md) . Raycast makes it easy to lint your extensions using the CLI's lint command (`ray lint`). Raycast provides by default an [opinionated ESLint configuration](https://github.com/raycast/eslint-config/blob/main/index.js) that includes everything you need to lint your Raycast extensions. The default configuration is as simple as this: Copy const { defineConfig } = require("eslint/config"); const raycastConfig = require("@raycast/eslint-config"); module.exports = defineConfig([...raycastConfig]); It abstracts away the different ESLint dependencies used for Raycast extensions and includes different rule-sets. It also includes Raycast's own ESLint plugin rule-set that makes it easier for you to follow best practices when building extension. For example, there's a [rule](https://github.com/raycast/eslint-plugin/blob/main/docs/rules/prefer-title-case.md) helping you follow the Title Case convention for `Action` components. You can check Raycast's ESLint plugin rules directly on the [repository documentation](https://github.com/raycast/eslint-plugin#rules) . [](https://developers.raycast.com/information/developer-tools/eslint#customization) Customization ------------------------------------------------------------------------------------------------------ You're free to turn on/off rules or add new plugins as you see fit for your extensions. For example, you could add the rule [`@raycast/prefer-placeholders`](https://github.com/raycast/eslint-plugin/blob/main/docs/rules/prefer-placeholders.md) for your extension: Copy const { defineConfig } = require("eslint/config"); const raycastConfig = require("@raycast/eslint-config"); module.exports = defineConfig([\ ...raycastConfig,\ {\ rules: {\ "@raycast/prefer-placeholders": "warn",\ },\ },\ ]); To keep the consistency of development experiences across extensions, we don't encourage adding too many personal ESLint preferences to an extension. [](https://developers.raycast.com/information/developer-tools/eslint#migration) Migration ---------------------------------------------------------------------------------------------- Starting with version 1.48.8, the ESLint configuration is included automatically when creating a new extension using the `Create Extension` command. If your extension was created before this version, you can migrate following the steps outlined on the [v1.48.8](https://developers.raycast.com/migration/v1.48.8) page. [PreviousCLI](https://developers.raycast.com/information/developer-tools/cli) [NextForked Extensions (community tool)](https://developers.raycast.com/information/developer-tools/forked-extensions) Last updated 6 months ago * [Customization](https://developers.raycast.com/information/developer-tools/eslint#customization) * [Migration](https://developers.raycast.com/information/developer-tools/eslint#migration) --- # showFailureToast | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/functions/showfailuretoast.md) . Function that shows a failure [Toast](https://developers.raycast.com/api-reference/feedback/toast) for a given Error. [](https://developers.raycast.com/utilities/functions/showfailuretoast#signature) Signature ------------------------------------------------------------------------------------------------ Copy function showFailureToast( error: unknown, options?: { title?: string; primaryAction?: Toast.ActionOptions; }, ): Promise; ### [](https://developers.raycast.com/utilities/functions/showfailuretoast#arguments) Arguments * `error` is the error to report. With a few options: * `options.title` is a string describing the action that failed. By default, `"Something went wrong"` * `options.primaryAction` is a Toast [Action](https://developers.raycast.com/api-reference/feedback/toast#toast.actionoptions) . ### [](https://developers.raycast.com/utilities/functions/showfailuretoast#return) Return Returns a [Toast](https://developers.raycast.com/api-reference/feedback/toast) . [](https://developers.raycast.com/utilities/functions/showfailuretoast#example) Example -------------------------------------------------------------------------------------------- [PreviousrunPowerShellScript](https://developers.raycast.com/utilities/functions/runpowershellscript) [NextwithCache](https://developers.raycast.com/utilities/functions/withcache) Last updated 2 years ago * [Signature](https://developers.raycast.com/utilities/functions/showfailuretoast#signature) * [Arguments](https://developers.raycast.com/utilities/functions/showfailuretoast#arguments) * [Return](https://developers.raycast.com/utilities/functions/showfailuretoast#return) * [Example](https://developers.raycast.com/utilities/functions/showfailuretoast#example) Copy import { showHUD } from "@raycast/api"; import { runAppleScript, showFailureToast } from "@raycast/utils"; export default async function () { try { const res = await runAppleScript( ` on run argv return "hello, " & item 1 of argv & "." end run `, ["world"], ); await showHUD(res); } catch (error) { showFailureToast(error, { title: "Could not run AppleScript" }); } } --- # getProgressIcon | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/icons/getprogressicon.md) . Icon to represent the progress of a task, a project, _something_. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-8d31dd8b07fabd4eba1a4ab2d4f256bc50f0fb9c%252Futils-progress-icon.png%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=5cf2bccc&sv=2) Progress Icon example [](https://developers.raycast.com/utilities/icons/getprogressicon#signature) Signature ------------------------------------------------------------------------------------------- * `progress` is a number between 0 and 1 (0 meaning not started, 1 meaning finished). * `color` is a Raycast `Color` or a hexadecimal representation of a color. By default it will be `Color.Red`. * `options.background` is a Raycast `Color` or a hexadecimal representation of a color for the background of the progress icon. By default, it will be `white` if the Raycast's appearance is `dark`, and `black` if the appearance is `light`. * `options.backgroundOpacity` is the opacity of the background of the progress icon. By default, it will be `0.1`. Returns an [Image.Asset](https://developers.raycast.com/api-reference/user-interface/icons-and-images) that can be used where Raycast expects them. [](https://developers.raycast.com/utilities/icons/getprogressicon#example) Example --------------------------------------------------------------------------------------- [PreviousgetFavicon](https://developers.raycast.com/utilities/icons/getfavicon) [NextOAuth Utils](https://developers.raycast.com/utilities/oauth) Last updated 1 year ago * [Signature](https://developers.raycast.com/utilities/icons/getprogressicon#signature) * [Example](https://developers.raycast.com/utilities/icons/getprogressicon#example) Copy function getProgressIcon( progress: number, color?: Color | string, options?: { background?: Color | string; backgroundOpacity?: number; }, ): Image.Asset; Copy import { List } from "@raycast/api"; import { getProgressIcon } from "@raycast/utils"; export default function Command() { return ( ); } --- # Window Management | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/window-management.md) . The Window Management API provides developers with some functions to create commands with some advanced logic to move [Window](https://developers.raycast.com/api-reference/window-management#windowmanagement.window) s around. Some users might not have access to this API. If a user doesn't have access to Raycast Pro, they will be asked if they want to get access when your extension calls the Window Management API. If the user doesn't wish to get access, the API call will throw an error. You can check if a user has access to the API using [`environment.canAccess(WindowManagement)`](https://developers.raycast.com/api-reference/environment) . The API is not accessible on Windows for now. [](https://developers.raycast.com/api-reference/window-management#api-reference) API Reference --------------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/window-management#windowmanagement.getactivewindow) WindowManagement.getActiveWindow Gets the active [Window](https://developers.raycast.com/api-reference/window-management#windowmanagement.window) . #### [](https://developers.raycast.com/api-reference/window-management#signature) Signature Copy async function getActiveWindow(): Promise; #### [](https://developers.raycast.com/api-reference/window-management#example) Example Copy import { WindowManagement, showToast } from "@raycast/api"; export default async function Command() { try { const window = await WindowManagement.getActiveWindow(); if (window.positionable) { await WindowManagement.setWindowBounds({ id: window.id, bounds: { position: { x: 100 } } }); } } catch (error) { showToast({ title: `Could not move window: ${error.message}`, style: Toast.Style.Failure }); } } #### [](https://developers.raycast.com/api-reference/window-management#return) Return A Promise that resolves with the active [Window](https://developers.raycast.com/api-reference/window-management#windowmanagement.window) . If no window is active, the promise will be rejected. ### [](https://developers.raycast.com/api-reference/window-management#windowmanagement.getwindowsonactivedesktop) WindowManagement.getWindowsOnActiveDesktop Gets the list of [Window](https://developers.raycast.com/api-reference/window-management#windowmanagement.window) s on the active [Desktop](https://developers.raycast.com/api-reference/window-management#windowmanagement.desktop) . #### [](https://developers.raycast.com/api-reference/window-management#signature-1) Signature #### [](https://developers.raycast.com/api-reference/window-management#example-1) Example #### [](https://developers.raycast.com/api-reference/window-management#return-1) Return A Promise that resolves with an array of Windows. ### [](https://developers.raycast.com/api-reference/window-management#windowmanagement.getdesktops) WindowManagement.getDesktops Gets the list of [Desktop](https://developers.raycast.com/api-reference/window-management#windowmanagement.desktop) s available across all screens. #### [](https://developers.raycast.com/api-reference/window-management#signature-2) Signature #### [](https://developers.raycast.com/api-reference/window-management#example-2) Example #### [](https://developers.raycast.com/api-reference/window-management#return-2) Return A Promise that resolves with the desktops. ### [](https://developers.raycast.com/api-reference/window-management#windowmanagement.setwindowbounds) WindowManagement.setWindowBounds Move a [Window](https://developers.raycast.com/api-reference/window-management#windowmanagement.window) or make it fullscreen. #### [](https://developers.raycast.com/api-reference/window-management#signature-3) Signature #### [](https://developers.raycast.com/api-reference/window-management#example-3) Example #### [](https://developers.raycast.com/api-reference/window-management#parameters) Parameters Name Description Type options\* `{ id: string }` or `{ bounds: { position?: { x?: number; y?: number }; size?: { height?: number; width?: number } }; desktopId?: string }` or `{ bounds: "fullscreen" }` #### [](https://developers.raycast.com/api-reference/window-management#return-3) Return A Promise that resolves with the window was moved. If the move isn't possible (for example trying to make a window fullscreen that doesn't support it), the promise will be rejected. [](https://developers.raycast.com/api-reference/window-management#types) Types ----------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/window-management#windowmanagement.window) WindowManagement.Window A Window from an [Application](https://developers.raycast.com/api-reference/utilities#application) on a [Desktop](https://developers.raycast.com/api-reference/window-management#windowmanagement.desktop) . #### [](https://developers.raycast.com/api-reference/window-management#properties) Properties Property Description Type active\* `boolean` bounds\* `{ position: { x: number; y: number }; size: { height: number; width: number } }` or `"fullscreen"` desktopId\* `string` fullScreenSettable\* `boolean` id\* `string` positionable\* `boolean` resizable\* `boolean` application [`Application`](https://developers.raycast.com/api-reference/utilities#application) ### [](https://developers.raycast.com/api-reference/window-management#windowmanagement.desktop) WindowManagement.Desktop A Desktop represents a virtual desktop on a Screen. #### [](https://developers.raycast.com/api-reference/window-management#properties-1) Properties Property Description Type active\* `boolean` id\* `string` screenId\* `string` size\* `{ height: number; width: number }` type\* [`WindowManagement.DesktopType`](https://developers.raycast.com/api-reference/window-management#windowmanagement.desktoptype) ### [](https://developers.raycast.com/api-reference/window-management#windowmanagement.desktoptype) WindowManagement.DesktopType The type of a [Desktop](https://developers.raycast.com/api-reference/window-management#windowmanagement.desktop) . #### [](https://developers.raycast.com/api-reference/window-management#enumeration-members) Enumeration members Name Description User The default Desktop type. It can contain any number of [Window](https://developers.raycast.com/api-reference/window-management#windowmanagement.window) FullScreen A Desktop made of a single fullscreen window [PreviousTool](https://developers.raycast.com/api-reference/tool) [NextGetting Started](https://developers.raycast.com/utilities/getting-started) Last updated 10 months ago * [API Reference](https://developers.raycast.com/api-reference/window-management#api-reference) * [WindowManagement.getActiveWindow](https://developers.raycast.com/api-reference/window-management#windowmanagement.getactivewindow) * [WindowManagement.getWindowsOnActiveDesktop](https://developers.raycast.com/api-reference/window-management#windowmanagement.getwindowsonactivedesktop) * [WindowManagement.getDesktops](https://developers.raycast.com/api-reference/window-management#windowmanagement.getdesktops) * [WindowManagement.setWindowBounds](https://developers.raycast.com/api-reference/window-management#windowmanagement.setwindowbounds) * [Types](https://developers.raycast.com/api-reference/window-management#types) * [WindowManagement.Window](https://developers.raycast.com/api-reference/window-management#windowmanagement.window) * [WindowManagement.Desktop](https://developers.raycast.com/api-reference/window-management#windowmanagement.desktop) * [WindowManagement.DesktopType](https://developers.raycast.com/api-reference/window-management#windowmanagement.desktoptype) Copy async function getWindowsOnActiveDesktop(): Promise; Copy import { WindowManagement, showToast } from "@raycast/api"; export default async function Command() { const windows = await WindowManagement.getWindowsOnActiveDesktop(); const chrome = windows.find((x) => x.application?.bundleId === "com.google.Chrome"); if (!chrome) { showToast({ title: "Couldn't find chrome", style: Toast.Style.Failure }); return; } WindowManagement.setWindowBounds({ id: chrome.id, bounds: { position: { x: 100 } } }); } Copy async function getDesktops(): Promise; Copy import { WindowManagement, showToast } from "@raycast/api"; export default function Command() { const desktops = await WindowManagement.getDesktops(); const screens = Set(desktops.map((desktop) => desktop.screenId)); showToast({ title: `Found ${desktops.length} desktops on ${screens.size} screens.` }); } Copy async function setWindowBounds( options: { id: string } & ( | { bounds: { position?: { x?: number; y?: number }; size?: { width?: number; height?: number }; }; desktopId?: string; } | { bounds: "fullscreen"; } ) ): Promise; Copy import { WindowManagement, showToast } from "@raycast/api"; export default async function Command() { try { const window = await WindowManagement.getActiveWindow(); if (window.positionable) { await WindowManagement.setWindowBounds({ id: window.id, bounds: { position: { x: 100 } } }); } } catch (error) { showToast({ title: `Could not move window: ${error.message}`, style: Toast.Style.Failure }); } } --- # getFavicon | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/icons/getfavicon.md) . Icon showing the favicon of a website. A favicon (favorite icon) is a tiny icon included along with a website, which is displayed in places like the browser's address bar, page tabs, and bookmarks menu. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-8383499b76a723de43e610079031cd2543c52a66%252Futils-favicon.png%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=64aa965f&sv=2) Favicon example [](https://developers.raycast.com/utilities/icons/getfavicon#signature) Signature -------------------------------------------------------------------------------------- * `name` is a string of the subject's name. * `options.fallback` is a [Image.Fallback](https://developers.raycast.com/api-reference/user-interface/icons-and-images#image.fallback) icon in case the Favicon is not found. By default, the fallback will be `Icon.Link`. * `options.size` is the size of the returned favicon. By default, it is 64 pixels. * `options.mask` is the size of the [Image.Mask](https://developers.raycast.com/api-reference/user-interface/icons-and-images#image.mask) to apply to the favicon. Returns an [Image.ImageLike](https://developers.raycast.com/api-reference/user-interface/icons-and-images) that can be used where Raycast expects them. [](https://developers.raycast.com/utilities/icons/getfavicon#example) Example ---------------------------------------------------------------------------------- [PreviousgetAvatarIcon](https://developers.raycast.com/utilities/icons/getavataricon) [NextgetProgressIcon](https://developers.raycast.com/utilities/icons/getprogressicon) Last updated 1 year ago * [Signature](https://developers.raycast.com/utilities/icons/getfavicon#signature) * [Example](https://developers.raycast.com/utilities/icons/getfavicon#example) Copy function getFavicon( url: string | URL, options?: { fallback?: Image.Fallback; size?: boolean; mask?: Image.Mask; }, ): Image.ImageLike; Copy import { List } from "@raycast/api"; import { getFavicon } from "@raycast/utils"; export default function Command() { return ( ); } --- # System Utilities | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/utilities.md) . This set of utilities exposes some of Raycast's native functionality to allow deep integration into the user's setup. For example, you can use the Application APIs to check if a desktop application is installed and then provide an action to deep-link into it. [](https://developers.raycast.com/api-reference/utilities#api-reference) API Reference ------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/utilities#getapplications) getApplications Returns all applications that can open the file or URL. #### [](https://developers.raycast.com/api-reference/utilities#signature) Signature Copy async function getApplications(path?: PathLike): Promise; #### [](https://developers.raycast.com/api-reference/utilities#example) Example Find Application List Installed Applications Copy import { getApplications, Application } from "@raycast/api"; // it is a lot more reliable to get an app by its bundle ID than its path async function findApplication(bundleId: string): Application | undefined { const installedApplications = await getApplications(); return installedApplications.filter((application) => application.bundleId == bundleId); } Copy import { getApplications } from "@raycast/api"; export default async function Command() { const installedApplications = await getApplications(); console.log("The following applications are installed on your Mac:"); console.log(installedApplications.map((a) => a.name).join(", ")); } #### [](https://developers.raycast.com/api-reference/utilities#parameters) Parameters Name Description Type path The path of the file or folder to get the applications for. If no path is specified, all installed applications are returned. `"fs".PathLike` #### [](https://developers.raycast.com/api-reference/utilities#return) Return An array of [Application](https://developers.raycast.com/api-reference/utilities#application) . ### [](https://developers.raycast.com/api-reference/utilities#getdefaultapplication) getDefaultApplication Returns the default application that the file or URL would be opened with. #### [](https://developers.raycast.com/api-reference/utilities#signature-1) Signature #### [](https://developers.raycast.com/api-reference/utilities#example-1) Example #### [](https://developers.raycast.com/api-reference/utilities#parameters-1) Parameters Name Description Type path\* The path of the file or folder to get the default application for. `"fs".PathLike` #### [](https://developers.raycast.com/api-reference/utilities#return-1) Return A Promise that resolves with the default [Application](https://developers.raycast.com/api-reference/utilities#application) that would open the file or URL. If no application was found, the promise will be rejected. ### [](https://developers.raycast.com/api-reference/utilities#getfrontmostapplication) getFrontmostApplication Returns the frontmost application. #### [](https://developers.raycast.com/api-reference/utilities#signature-2) Signature #### [](https://developers.raycast.com/api-reference/utilities#example-2) Example #### [](https://developers.raycast.com/api-reference/utilities#return-2) Return A Promise that resolves with the frontmost [Application](https://developers.raycast.com/api-reference/utilities#application) . If no application was found, the promise will be rejected. ### [](https://developers.raycast.com/api-reference/utilities#showinfinder) showInFinder Shows a file or directory in the Finder. #### [](https://developers.raycast.com/api-reference/utilities#signature-3) Signature #### [](https://developers.raycast.com/api-reference/utilities#example-3) Example #### [](https://developers.raycast.com/api-reference/utilities#parameters-2) Parameters Name Description Type path\* The path to show in the Finder. `"fs".PathLike` #### [](https://developers.raycast.com/api-reference/utilities#return-3) Return A Promise that resolves when the item is revealed in the Finder. ### [](https://developers.raycast.com/api-reference/utilities#trash) trash Moves a file or directory to the Trash. #### [](https://developers.raycast.com/api-reference/utilities#signature-4) Signature #### [](https://developers.raycast.com/api-reference/utilities#example-4) Example #### [](https://developers.raycast.com/api-reference/utilities#parameters-3) Parameters Name Description Type path\* The item or items to move to the trash. `"fs".PathLike` or `"fs".PathLike[]` #### [](https://developers.raycast.com/api-reference/utilities#return-4) Return A Promise that resolves when all files are moved to the trash. ### [](https://developers.raycast.com/api-reference/utilities#open) open Opens a target with the default application or specified application. #### [](https://developers.raycast.com/api-reference/utilities#signature-5) Signature #### [](https://developers.raycast.com/api-reference/utilities#example-5) Example #### [](https://developers.raycast.com/api-reference/utilities#parameters-4) Parameters Name Description Type target\* The file, folder or URL to open. `string` application The application name to use for opening the file. If no application is specified, the default application as determined by the system is used to open the specified file. Note that you can use the application name, app identifier, or absolute path to the app. `string` or [`Application`](https://developers.raycast.com/api-reference/utilities#application) #### [](https://developers.raycast.com/api-reference/utilities#return-5) Return A Promise that resolves when the target has been opened. ### [](https://developers.raycast.com/api-reference/utilities#captureexception) captureException Report the provided exception to the Developer Hub. This helps in handling failures gracefully while staying informed about the occurrence of the failure. #### [](https://developers.raycast.com/api-reference/utilities#signature-6) Signature #### [](https://developers.raycast.com/api-reference/utilities#example-6) Example #### [](https://developers.raycast.com/api-reference/utilities#parameters-5) Parameters Name Description Type exception\* The exception you want to report. `unknown` [](https://developers.raycast.com/api-reference/utilities#types) Types --------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/utilities#application) Application An object that represents a locally installed application on the system. It can be used to open files or folders in a specific application. Use [getApplications](https://developers.raycast.com/api-reference/utilities#getapplications) or [getDefaultApplication](https://developers.raycast.com/api-reference/utilities#getdefaultapplication) to get applications that can open a specific file or folder. #### [](https://developers.raycast.com/api-reference/utilities#properties) Properties Property Description Type name\* The display name of the application. `string` path\* The absolute path to the application bundle, e.g. `/Applications/Raycast.app`, `string` bundleId The macOS bundle identifier of the application, e.g. `com.raycast.macos`. `string` localizedName The localized name of the application. `string` windowsAppId The Windows App ID of the application. `string` ### [](https://developers.raycast.com/api-reference/utilities#pathlike) PathLike Supported path types. [PreviousStorage](https://developers.raycast.com/api-reference/storage) [NextUser Interface](https://developers.raycast.com/api-reference/user-interface) Last updated 6 months ago * [API Reference](https://developers.raycast.com/api-reference/utilities#api-reference) * [getApplications](https://developers.raycast.com/api-reference/utilities#getapplications) * [getDefaultApplication](https://developers.raycast.com/api-reference/utilities#getdefaultapplication) * [getFrontmostApplication](https://developers.raycast.com/api-reference/utilities#getfrontmostapplication) * [showInFinder](https://developers.raycast.com/api-reference/utilities#showinfinder) * [trash](https://developers.raycast.com/api-reference/utilities#trash) * [open](https://developers.raycast.com/api-reference/utilities#open) * [captureException](https://developers.raycast.com/api-reference/utilities#captureexception) * [Types](https://developers.raycast.com/api-reference/utilities#types) * [Application](https://developers.raycast.com/api-reference/utilities#application) * [PathLike](https://developers.raycast.com/api-reference/utilities#pathlike) Copy async function getDefaultApplication(path: PathLike): Promise; Copy import { getDefaultApplication } from "@raycast/api"; export default async function Command() { const defaultApplication = await getDefaultApplication(__filename); console.log(`Default application for JavaScript is: ${defaultApplication.name}`); } Copy async function getFrontmostApplication(): Promise; Copy import { getFrontmostApplication } from "@raycast/api"; export default async function Command() { const frontmostApplication = await getFrontmostApplication(); console.log(`The frontmost application is: ${frontmostApplication.name}`); } Copy async function showInFinder(path: PathLike): Promise; Copy import { showInFinder } from "@raycast/api"; import { homedir } from "os"; import { join } from "path"; export default async function Command() { await showInFinder(join(homedir(), "Downloads")); } Copy async function trash(path: PathLike | PathLike[]): Promise; Copy import { trash } from "@raycast/api"; import { writeFile } from "fs/promises"; import { homedir } from "os"; import { join } from "path"; export default async function Command() { const file = join(homedir(), "Desktop", "yolo.txt"); await writeFile(file, "I will be deleted soon!"); await trash(file); } Copy async function open(target: string, application?: Application | string): Promise; Copy import { open } from "@raycast/api"; export default async function Command() { await open("https://www.raycast.com", "com.google.Chrome"); } Copy function captureException(exception: unknown): void; Copy import { open, captureException, showToast, Toast } from "@raycast/api"; export default async function Command() { const url = "https://www.raycast.com"; const app = "Google Chrome"; try { await open(url, app); } catch (e: unknown) { captureException(e); await showToast({ style: Toast.Style.Failure, title: `Could not open ${url} in ${app}.`, }); } } Copy PathLike: string | Buffer | URL; --- # Icons | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/icons.md) . [getAvatarIcon](https://developers.raycast.com/utilities/icons/getavataricon) [getFavicon](https://developers.raycast.com/utilities/icons/getfavicon) [getProgressIcon](https://developers.raycast.com/utilities/icons/getprogressicon) [PreviouswithCache](https://developers.raycast.com/utilities/functions/withcache) [NextgetAvatarIcon](https://developers.raycast.com/utilities/icons/getavataricon) Last updated 2 years ago --- # createDeeplink | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/functions/createdeeplink.md) . Function that creates a deeplink for an extension or script command. [](https://developers.raycast.com/utilities/functions/createdeeplink#signature) Signature ---------------------------------------------------------------------------------------------- There are three ways to use the function. The first one is for creating a deeplink to a command inside the current extension: Copy function createDeeplink(options: { type?: DeeplinkType.Extension, command: string, launchType?: LaunchType, arguments?: LaunchProps["arguments"], fallbackText?: string, }): string; The second one is for creating a deeplink to an extension that is not the current extension: Copy function createDeeplink(options: { type?: DeeplinkType.Extension, ownerOrAuthorName: string, extensionName: string, command: string, launchType?: LaunchType, arguments?: LaunchProps["arguments"], fallbackText?: string, }): string; The third one is for creating a deeplink to a script command: ### [](https://developers.raycast.com/utilities/functions/createdeeplink#arguments) Arguments #### [](https://developers.raycast.com/utilities/functions/createdeeplink#extension) Extension * `type` is the type of the deeplink. It must be `DeeplinkType.Extension`. * `command` is the name of the command to deeplink to. * `launchType` is the type of the launch. * `arguments` is an object that contains the arguments to pass to the command. * `fallbackText` is the text to show if the command is not available. * For intra-extension deeplinks: * `ownerOrAuthorName` is the name of the owner or author of the extension. * `extensionName` is the name of the extension. #### [](https://developers.raycast.com/utilities/functions/createdeeplink#script-command) Script command * `type` is the type of the deeplink. It must be `DeeplinkType.ScriptCommand`. * `command` is the name of the script command to deeplink to. * `arguments` is an array of strings to be passed as arguments to the script command. ### [](https://developers.raycast.com/utilities/functions/createdeeplink#return) Return Returns a string. [](https://developers.raycast.com/utilities/functions/createdeeplink#example) Example ------------------------------------------------------------------------------------------ [](https://developers.raycast.com/utilities/functions/createdeeplink#types) Types -------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/utilities/functions/createdeeplink#deeplinktype) DeeplinkType A type to denote whether the deeplink is for a script command or an extension. [PreviousFunctions](https://developers.raycast.com/utilities/functions) [NextexecuteSQL](https://developers.raycast.com/utilities/functions/executesql) Last updated 1 year ago * [Signature](https://developers.raycast.com/utilities/functions/createdeeplink#signature) * [Arguments](https://developers.raycast.com/utilities/functions/createdeeplink#arguments) * [Return](https://developers.raycast.com/utilities/functions/createdeeplink#return) * [Example](https://developers.raycast.com/utilities/functions/createdeeplink#example) * [Types](https://developers.raycast.com/utilities/functions/createdeeplink#types) * [DeeplinkType](https://developers.raycast.com/utilities/functions/createdeeplink#deeplinktype) Copy function createDeeplink(options: { type: DeeplinkType.ScriptCommand, command: string, arguments?: string[], }): string; Copy import { Action, ActionPanel, LaunchProps, List } from "@raycast/api"; import { createDeeplink, DeeplinkType } from "@raycast/utils"; export default function Command(props: LaunchProps<{ launchContext: { message: string } }>) { console.log(props.launchContext?.message); return ( } /> } /> } /> ); } Copy export enum DeeplinkType { /** A script command */ ScriptCommand = "script-command", /** An extension command */ Extension = "extension", } --- # runAppleScript | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/functions/runapplescript.md) . Function that executes an AppleScript script. Only available on macOS [](https://developers.raycast.com/utilities/functions/runapplescript#signature) Signature ---------------------------------------------------------------------------------------------- There are two ways to use the function. The first one should be preferred when executing a static script. Copy function runAppleScript( script: string, options?: { humanReadableOutput?: boolean; language?: "AppleScript" | "JavaScript"; signal?: AbortSignal; timeout?: number; parseOutput?: ParseExecOutputHandler; }, ): Promise; The second one can be used to pass arguments to a script. Copy function runAppleScript( script: string, arguments: string[], options?: { humanReadableOutput?: boolean; language?: "AppleScript" | "JavaScript"; signal?: AbortSignal; timeout?: number; parseOutput?: ParseExecOutputHandler; }, ): Promise; ### [](https://developers.raycast.com/utilities/functions/runapplescript#arguments) Arguments * `script` is the script to execute. * `arguments` is an array of strings to pass as arguments to the script. With a few options: * `options.humanReadableOutput` is a boolean to tell the script what form to output. By default, `runAppleScript` returns its results in human-readable form: strings do not have quotes around them, characters are not escaped, braces for lists and records are omitted, etc. This is generally more useful, but can introduce ambiguities. For example, the lists `{"foo", "bar"}` and `{{"foo", {"bar"}}}` would both be displayed as β€˜foo, bar’. To see the results in an unambiguous form that could be recompiled into the same value, set `humanReadableOutput` to `false`. * `options.language` is a string to specify whether the script is using [`AppleScript`](https://developer.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScriptLangGuide/introduction/ASLR_intro.html#//apple_ref/doc/uid/TP40000983) or [`JavaScript`](https://developer.apple.com/library/archive/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/Articles/Introduction.html#//apple_ref/doc/uid/TP40014508-CH111-SW1) . By default, it will assume that it's using `AppleScript`. * `options.signal` is a Signal object that allows you to abort the request if required via an AbortController object. * `options.timeout` is a number. If greater than `0`, the parent will send the signal `SIGTERM` if the script runs longer than timeout milliseconds. By default, the execution will timeout after 10000ms (eg. 10s). * `options.parseOutput` is a function that accepts the output of the script as an argument and returns the data the hooks will return - see [ParseExecOutputHandler](https://developers.raycast.com/utilities/functions/runapplescript#parseexecoutputhandler) . By default, the function will return `stdout` as a string. ### [](https://developers.raycast.com/utilities/functions/runapplescript#return) Return Returns a Promise which resolves to a string by default. You can control what it returns by passing `options.parseOutput`. [](https://developers.raycast.com/utilities/functions/runapplescript#example) Example ------------------------------------------------------------------------------------------ [](https://developers.raycast.com/utilities/functions/runapplescript#types) Types -------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/utilities/functions/runapplescript#parseexecoutputhandler) ParseExecOutputHandler A function that accepts the output of the script as an argument and returns the data the function will return. [PreviousexecuteSQL](https://developers.raycast.com/utilities/functions/executesql) [NextrunPowerShellScript](https://developers.raycast.com/utilities/functions/runpowershellscript) Last updated 1 year ago * [Signature](https://developers.raycast.com/utilities/functions/runapplescript#signature) * [Arguments](https://developers.raycast.com/utilities/functions/runapplescript#arguments) * [Return](https://developers.raycast.com/utilities/functions/runapplescript#return) * [Example](https://developers.raycast.com/utilities/functions/runapplescript#example) * [Types](https://developers.raycast.com/utilities/functions/runapplescript#types) * [ParseExecOutputHandler](https://developers.raycast.com/utilities/functions/runapplescript#parseexecoutputhandler) Copy import { showHUD } from "@raycast/api"; import { runAppleScript } from "@raycast/utils"; export default async function () { const res = await runAppleScript( ` on run argv return "hello, " & item 1 of argv & "." end run `, ["world"], ); await showHUD(res); } Copy export type ParseExecOutputHandler = (args: { /** The output of the script on stdout. */ stdout: string; /** The output of the script on stderr. */ stderr: string; error?: Error | undefined; /** The numeric exit code of the process that was run. */ exitCode: number | null; /** The name of the signal that was used to terminate the process. For example, SIGFPE. */ signal: NodeJS.Signals | null; /** Whether the process timed out. */ timedOut: boolean; /** The command that was run, for logging purposes. */ command: string; /** The options passed to the script, for logging purposes. */ options?: ExecOptions | undefined; }) => T; --- # User Interface | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/user-interface.md) . Raycast uses React for its user interface declaration and renders the supported elements to our native UI. The API comes with a set of UI components that you can use to build your extensions. Think of it as a design system. The high-level components are the following: * [List](https://developers.raycast.com/api-reference/user-interface/list) to show multiple similar items, f.e. a list of your open todos. * [Grid](https://developers.raycast.com/api-reference/user-interface/grid) similar to a List but with more legroom to show an image for each item, f.e. a collection of icons. * [Detail](https://developers.raycast.com/api-reference/user-interface/detail) to present more information, f.e. the details of a GitHub pull request. * [Form](https://developers.raycast.com/api-reference/user-interface/form) to create new content, f.e. filing a bug report. Each component can provide interaction via an [ActionPanel](https://developers.raycast.com/api-reference/user-interface/action-panel) . The panel has a list of [Actions](https://developers.raycast.com/api-reference/user-interface/actions) where each one can be associated with a [keyboard shortcut](https://developers.raycast.com/api-reference/keyboard) . Shortcuts allow users to use Raycast without using their mouse. [](https://developers.raycast.com/api-reference/user-interface#rendering) Rendering ---------------------------------------------------------------------------------------- To render a user interface, you need to do the following: * Set the `mode` to `view` in the [`package.json` manifest file](https://developers.raycast.com/information/manifest#command-properties) * Export a React component from your command entry file As a general rule of thumb, you should render something as quickly as possible. This guarantees that your command feels responsive. If you don't have data available to show, you can set the `isLoading` prop to `true` on top-level components such as [``](https://developers.raycast.com/api-reference/user-interface/detail) , [`
`](https://developers.raycast.com/api-reference/user-interface/form) , or [``](https://developers.raycast.com/api-reference/user-interface/list) . It shows a loading indicator at the top of Raycast. Here is an example that shows a loading indicator for 2 seconds after the command got launched: Copy import { List } from "@raycast/api"; import { useEffect, useState } from "react"; export default function Command() { const [isLoading, setIsLoading] = useState(true); useEffect(() => { setTimeout(() => setIsLoading(false), 2000); }, []); return {/* Render your data */}; } [PreviousSystem Utilities](https://developers.raycast.com/api-reference/utilities) [NextAction Panel](https://developers.raycast.com/api-reference/user-interface/action-panel) Last updated 2 years ago --- # AI | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/ai.md) . The AI API provides developers with seamless access to AI functionality without requiring API keys, configuration, or extra dependencies. Some users might not have access to this API. If a user doesn't have access to Raycast Pro, they will be asked if they want to get access when your extension calls the AI API. If the user doesn't wish to get access, the API call will throw an error. You can check if a user has access to the API using [`environment.canAccess(AI)`](https://developers.raycast.com/api-reference/environment) . [](https://developers.raycast.com/api-reference/ai#api-reference) API Reference ------------------------------------------------------------------------------------ ### [](https://developers.raycast.com/api-reference/ai#ai.ask) AI.ask Ask AI anything you want. Use this in β€œno-view” Commands, effects, or callbacks. In a React component, you might want to use the [useAI util hook](https://developers.raycast.com/utilities/react-hooks/useai) instead. #### [](https://developers.raycast.com/api-reference/ai#signature) Signature Copy async function ask(prompt: string, options?: AskOptions): Promise & EventEmitter; #### [](https://developers.raycast.com/api-reference/ai#example) Example Basic Usage Error handling Stream answer User Feedback Check for access Copy import { AI, Clipboard } from "@raycast/api"; export default async function command() { const answer = await AI.ask("Suggest 5 jazz songs"); await Clipboard.copy(answer); } Copy import { AI, showToast, Toast } from "@raycast/api"; export default async function command() { try { await AI.ask("Suggest 5 jazz songs"); } catch (error) { // Handle error here, eg: by showing a Toast await showToast({ style: Toast.Style.Failure, title: "Failed to generate answer", }); } } Copy import { AI, getSelectedFinderItems, showHUD } from "@raycast/api"; import fs from "fs"; export default async function main() { let allData = ""; const [file] = await getSelectedFinderItems(); const answer = AI.ask("Suggest 5 jazz songs"); // Listen to "data" event to stream the answer answer.on("data", async (data) => { allData += data; await fs.promises.writeFile(`${file.path}`, allData.trim(), "utf-8"); }); await answer; await showHUD("Done!"); } #### [](https://developers.raycast.com/api-reference/ai#parameters) Parameters Name Description Type prompt\* The prompt to ask the AI. `string` options Options to control which and how the AI model should behave. [`AI.AskOptions`](https://developers.raycast.com/api-reference/ai#ai.askoptions) #### [](https://developers.raycast.com/api-reference/ai#return) Return A Promise that resolves with a prompt completion. [](https://developers.raycast.com/api-reference/ai#types) Types -------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/ai#ai.creativity) AI.Creativity Concrete tasks, such as fixing grammar, require less creativity while open-ended questions, such as generating ideas, require more. If a number is passed, it needs to be in the range 0-2. For larger values, 2 will be used. For lower values, 0 will be used. ### [](https://developers.raycast.com/api-reference/ai#ai.model) AI.Model The AI model to use to answer to the prompt. Defaults to `AI.Model["OpenAI_GPT-4o_mini"]`. Model Description OpenAI\_GPT-5\_mini OpenAI's latest model, great for well-defined tasks and precise prompts. OpenAI\_GPT-5\_nano OpenAI's latest model, great for summarization and classification tasks. OpenAI\_GPT-4.1 OpenAI's flagship model optimized for complex problem solving. OpenAI\_GPT-4.1\_mini Balanced GPT-4.1 variant optimized for speed and cost efficiency. OpenAI\_GPT-4.1\_nano Fastest and most cost-effective GPT-4.1 variant. OpenAI\_GPT-4 Previous generation GPT-4 model with broad knowledge and complex instruction handling. OpenAI\_GPT-4\_Turbo Previous generation GPT-4 with expanded context window. OpenAI\_GPT-4o Advanced OpenAI model optimized for speed and complex problem solving. OpenAI\_GPT-4o\_mini Fast and intelligent model for everyday tasks. OpenAI\_GPT-5 OpenAI's latest model, great for coding and agentic tasks across domains. OpenAI\_GPT-5.1 OpenAI's model with adaptive reasoning, great for coding and agentic tasks across domains. OpenAI\_GPT-5.1\_Codex A version of GPT-5.1 optimized for agentic coding tasks in Codex or similar environments. OpenAI\_GPT-5.1\_Instant OpenAI's fastest GPT-5.1 model with adaptive reasoning, optimized for speed and efficiency. OpenAI\_GPT-5.2 OpenAI's most capable model for professional work and long-running agents with state-of-the-art tool-calling. OpenAI\_GPT-5.2\_Instant OpenAI's fast, capable model for everyday work with improved info-seeking, how-tos, and technical writing. OpenAI\_GPT-5.3\_Instant OpenAI's fast, capable model for everyday work with improved info-seeking, how-tos, and technical writing. OpenAI\_GPT-5.3\_Codex A version of GPT-5.3 optimized for agentic coding tasks in Codex or similar environments. OpenAI\_GPT-5.4 OpenAI's most capable model for professional work and long-running agents with state-of-the-art tool-calling. OpenAI\_GPT-5.4\_mini OpenAI's strongest mini model yet for coding and agentic workflows. OpenAI\_GPT-5.4\_nano OpenAI's cheapest GPT-5.4-class model for simpler tasks. OpenAI\_o3 Advanced model excelling in math, science, coding, and visual tasks. OpenAI\_o4-mini Fast, efficient model optimized for coding and visual tasks. OpenAI\_o1 Advanced reasoning model for complex STEM problems. OpenAI\_o3-mini Fast reasoning model optimized for STEM tasks. Groq\_GPT-OSS\_20b OpenAI's first open-source model, 20b variant. Groq\_GPT-OSS\_120b OpenAI's first open-source model, 120b variant. Anthropic\_Claude\_4.5\_Haiku Anthropic's offering focusing on being the best combination of performance and speed. Anthropic\_Claude\_4\_Sonnet Anthropic's previous generation Sonnet model with strong general capabilities. Anthropic\_Claude\_4.5\_Sonnet Anthropic's previous generation Sonnet model with high intelligence across most tasks. Anthropic\_Claude\_4.6\_Sonnet Anthropic's most intelligent model with the highest intelligence across most tasks. Anthropic\_Claude\_4.5\_Opus Anthropic's previous generation Opus model with enhanced capabilities. Anthropic\_Claude\_4.6\_Opus Anthropic's model for complex tasks with exceptional fluency. Anthropic\_Claude\_4.7\_Opus Anthropic's most powerful model with combined reasoning and non-reasoning capabilities. Perplexity\_Sonar Fast Perplexity model with integrated search capabilities. Perplexity\_Sonar\_Pro Advanced Perplexity model for complex queries with search integration. Groq\_Llama\_4\_Scout Advanced 17B parameter multimodal model with 16 experts. Groq\_Llama\_3.3\_70B Meta's state-of-the-art model for reasoning and general knowledge. Groq\_Llama\_3.1\_8B Fast, instruction-optimized open-source model. Mistral\_Nemo Small, Apache-licensed model built with NVIDIA. Mistral\_Large Top-tier reasoning model with strong multilingual support. Mistral\_Medium A powerful, cost-effective, frontier-class multimodal model. Mistral\_Small\_3 Latest enterprise-grade small model with improved reasoning. Mistral\_Codestral Specialized model for code-related tasks and testing. Groq\_Qwen3-32B The latest generation of large language models in the Qwen series. Google\_Gemini\_3.1\_Flash\_Lite Ultra-fast, cost-effective model for high-volume tasks and lightweight agentic workflows. Google\_Gemini\_3\_Flash Fast thinking model with strong balance of speed, performance, and value. Google\_Gemini\_3.1\_Pro Next generation thinking model for complex problem solving. Google\_Gemini\_2.5\_Pro Previous generation thinking model for complex problem solving. Google\_Gemini\_2.5\_Flash Fast, well-rounded thinking model. Google\_Gemini\_2.5\_Flash\_Lite Fast model optimized for large-scale text output. Together\_AI\_Qwen3-235B-A22B-Instruct-2507-tput A varied model with enhanced reasoning. Together\_AI\_DeepSeek-R1 Open-source model matching OpenAI-o1 performance. Together\_AI\_DeepSeek-V3 Advanced Mixture-of-Experts model. Together\_AI\_Kimi\_K2.5 Kimi K2.5 is an advanced multimodal AI model with improved reasoning and instruction-following capabilities. xAI\_Grok-4.1\_Fast xAI's best agentic tool calling model that shines in real-world use cases like customer support and deep research. xAI\_Grok-4.20 xAI's advanced reasoning model with enhanced capabilities. xAI\_Grok-4 Advanced language model with enhanced reasoning and tool capabilities. xAI\_Grok-4\_Fast xAI's latest advancement in cost-efficient reasoning models. xAI\_Grok\_Code\_Fast\_1 Grok Code Fast 1 is xAI's Coding Agent focused model xAI\_Grok-3\_Beta Enterprise-focused model for data, coding, and summarization tasks. xAI\_Grok-3\_Mini\_Beta Fast, lightweight model for logic-based tasks. If a model isn't available to the user (or has been disabled by the user), Raycast will fallback to a similar one. ### [](https://developers.raycast.com/api-reference/ai#ai.askoptions) AI.AskOptions #### [](https://developers.raycast.com/api-reference/ai#properties) Properties Property Description Type creativity Concrete tasks, such as fixing grammar, require less creativity while open-ended questions, such as generating ideas, require more. If a number is passed, it needs to be in the range 0-2. For larger values, 2 will be used. For lower values, 0 will be used. [`AI.Creativity`](https://developers.raycast.com/api-reference/ai#ai.creativity) model The AI model to use to answer to the prompt. [`AI.Model`](https://developers.raycast.com/api-reference/ai#ai.model) signal Abort signal to cancel the request. [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) [](https://developers.raycast.com/api-reference/ai#rate-limit) Rate Limit ------------------------------------------------------------------------------ To prevent accidental programmatic over-usage of AI quota, Raycast enforces rate limits on AI requests made from extensions. Limit per minute Limit per hour 10/minute 100/hour [PreviousVersioning](https://developers.raycast.com/information/versioning) [NextBrowser Extension](https://developers.raycast.com/api-reference/browser-extension) Last updated 2 months ago * [API Reference](https://developers.raycast.com/api-reference/ai#api-reference) * [AI.ask](https://developers.raycast.com/api-reference/ai#ai.ask) * [Types](https://developers.raycast.com/api-reference/ai#types) * [AI.Creativity](https://developers.raycast.com/api-reference/ai#ai.creativity) * [AI.Model](https://developers.raycast.com/api-reference/ai#ai.model) * [AI.AskOptions](https://developers.raycast.com/api-reference/ai#ai.askoptions) * [Rate Limit](https://developers.raycast.com/api-reference/ai#rate-limit) Copy import { AI, getSelectedFinderItems, showHUD } from "@raycast/api"; import fs from "fs"; export default async function main() { let allData = ""; const [file] = await getSelectedFinderItems(); // If you're doing something that happens in the background // Consider showing a HUD or a Toast as the first step // To give users feedback about what's happening await showHUD("Generating answer..."); const answer = await AI.ask("Suggest 5 jazz songs"); await fs.promises.writeFile(`${file.path}`, allData.trim(), "utf-8"); // Then, when everythig is done, notify the user again await showHUD("Done!"); } Copy import { AI, getSelectedFinderItems, showHUD, environment } from "@raycast/api"; import fs from "fs"; export default async function main() { if (environment.canAccess(AI)) { const answer = await AI.ask("Suggest 5 jazz songs"); await Clipboard.copy(answer); } else { await showHUD("You don't have access :("); } } Copy type Creativity = "none" | "low" | "medium" | "high" | "maximum" | number; --- # OAuth Utils | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/oauth.md) . Dealing with OAuth can be tedious. So we've built a set of utilities to make that task way easier. There are two part to our utilities: 1. Authenticating with a service using [OAuthService](https://developers.raycast.com/utilities/oauth/oauthservice) or built-in providers (e.g GitHub with `OAuthService.github`) 2. Bringing authentication to Raycast commands using [withAccessToken](https://developers.raycast.com/utilities/oauth/withaccesstoken) and [`getAccessToken`](https://developers.raycast.com/utilities/oauth/getaccesstoken) `OAuthService`, `withAccessToken`, and `getAccessToken` are designed to work together. You'll find below different use cases for which you can use these utils. [](https://developers.raycast.com/utilities/oauth#using-a-built-in-provider) Using a built-in provider ----------------------------------------------------------------------------------------------------------- We provide built-in providers that you can use out of the box, such as GitHub or Linear. You don't need to configure anything for them apart from the scope your extension requires. Copy import { Detail, LaunchProps } from "@raycast/api"; import { withAccessToken, getAccessToken, OAuthService } from "@raycast/utils"; const github = OAuthService.github({ scope: "notifications repo read:org read:user read:project", }); function AuthorizedComponent(props: LaunchProps) { const { token } = getAccessToken(); return ; } export default withAccessToken(github)(AuthorizedComponent); You can see our different providers on the following page: [OAuthService](https://developers.raycast.com/utilities/oauth/oauthservice) [](https://developers.raycast.com/utilities/oauth#using-your-own-client) Using your own client --------------------------------------------------------------------------------------------------- [](https://developers.raycast.com/utilities/oauth#using-onauthorize-to-initialize-an-sdk-or-similar) Using `onAuthorize` to initialize an SDK or similar ------------------------------------------------------------------------------------------------------------------------------------------------------------- This example is useful in cases where you want to initialize a third-party client and share it throughout your codebase. [PreviousgetProgressIcon](https://developers.raycast.com/utilities/icons/getprogressicon) [NextOAuthService](https://developers.raycast.com/utilities/oauth/oauthservice) Last updated 2 years ago * [Using a built-in provider](https://developers.raycast.com/utilities/oauth#using-a-built-in-provider) * [Using your own client](https://developers.raycast.com/utilities/oauth#using-your-own-client) * [Using onAuthorize to initialize an SDK or similar](https://developers.raycast.com/utilities/oauth#using-onauthorize-to-initialize-an-sdk-or-similar) Copy import { OAuth, Detail, LaunchProps } from "@raycast/api"; import { withAccessToken, getAccessToken, OAuthService } from "@raycast/utils"; const client = new OAuth.PKCEClient({ redirectMethod: OAuth.RedirectMethod.Web, providerName: "Your Provider Name", providerIcon: "provider_icon.png", providerId: "yourProviderId", description: "Connect your {PROVIDER_NAME} account", }); const provider = new OAuthService({ client, clientId: "YOUR_CLIENT_ID", scope: "YOUR_SCOPES", authorizeUrl: "YOUR_AUTHORIZE_URL", tokenUrl: "YOUR_TOKEN_URL", }); function AuthorizedComponent(props: LaunchProps) { const { token } = getAccessToken(); return ; } export default withAccessToken(provider)(AuthorizedComponent); Copy import { OAuthService } from "@raycast/utils"; import { LinearClient, LinearGraphQLClient } from "@linear/sdk"; let linearClient: LinearClient | null = null; export const linear = OAuthService.linear({ scope: "read write", onAuthorize({ token }) { linearClient = new LinearClient({ accessToken: token }); }, }); export function withLinearClient(Component: React.ComponentType) { return withAccessToken(linear)(Component); } export function getLinearClient(): { linearClient: LinearClient; graphQLClient: LinearGraphQLClient } { if (!linearClient) { throw new Error("No linear client initialized"); } return { linearClient, graphQLClient: linearClient.client }; } --- # getAccessToken | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/oauth/getaccesstoken.md) . Utility function designed for retrieving authorization tokens within a component. It ensures that your React components have the necessary authentication state, either through OAuth or a personal access token. `getAccessToken` **must** be used within components that are nested inside a component wrapped with [`withAccessToken`](https://developers.raycast.com/utilities/oauth/withaccesstoken) . Otherwise, the function will fail with an error. [](https://developers.raycast.com/utilities/oauth/getaccesstoken#signature) Signature ------------------------------------------------------------------------------------------ Copy function getAccessToken(): { token: string; type: "oauth" | "personal"; }; ### [](https://developers.raycast.com/utilities/oauth/getaccesstoken#return) Return The function returns an object containing the following properties: * `token`: A string representing the access token. * `type`: An optional string that indicates the type of token retrieved. It can either be `oauth` for OAuth tokens or `personal` for personal access tokens. [](https://developers.raycast.com/utilities/oauth/getaccesstoken#example) Example -------------------------------------------------------------------------------------- Copy import { Detail } from "@raycast/api"; import { authorize } from "./oauth"; function AuthorizedComponent() { const { token } = getAccessToken(); return ; } export default withAccessToken({ authorize })(AuthorizedComponent); [PreviouswithAccessToken](https://developers.raycast.com/utilities/oauth/withaccesstoken) [NextGetting a Google client ID](https://developers.raycast.com/utilities/oauth/getting-google-client-id) Last updated 2 years ago * [Signature](https://developers.raycast.com/utilities/oauth/getaccesstoken#signature) * [Return](https://developers.raycast.com/utilities/oauth/getaccesstoken#return) * [Example](https://developers.raycast.com/utilities/oauth/getaccesstoken#example) --- # Navigation | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/user-interface/navigation.md) . [](https://developers.raycast.com/api-reference/user-interface/navigation#api-reference) API Reference ----------------------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/user-interface/navigation#usenavigation) useNavigation A hook that lets you push and pop view components in the navigation stack. You most likely won't use this hook too often. To push a new component, use the [Push Action](https://developers.raycast.com/api-reference/user-interface/actions#action.push) . When a user presses `ESC`, we automatically pop to the previous component. #### [](https://developers.raycast.com/api-reference/user-interface/navigation#signature) Signature Copy function useNavigation(): Navigation; #### [](https://developers.raycast.com/api-reference/user-interface/navigation#example) Example Copy import { Action, ActionPanel, Detail, useNavigation } from "@raycast/api"; function Ping() { const { push } = useNavigation(); return ( push()} /> } /> ); } function Pong() { const { pop } = useNavigation(); return ( } /> ); } export default function Command() { return ; } #### [](https://developers.raycast.com/api-reference/user-interface/navigation#return) Return A [Navigation](https://developers.raycast.com/api-reference/user-interface/navigation#navigation) object with [Navigation.push](https://developers.raycast.com/api-reference/user-interface/navigation#navigation) and [Navigation.pop](https://developers.raycast.com/api-reference/user-interface/navigation#navigation) functions. Use the functions to alter the navigation stack. [](https://developers.raycast.com/api-reference/user-interface/navigation#types) Types ------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/user-interface/navigation#navigation) Navigation Return type of the [useNavigation](https://developers.raycast.com/api-reference/user-interface/navigation#usenavigation) hook to perform push and pop actions. #### [](https://developers.raycast.com/api-reference/user-interface/navigation#properties) Properties Property Description Type pop\* Pop current view component from the navigation stack. `() => void` push\* Push a new view component to the navigation stack. `(component: React.ReactNode, onPop: () => void) => void` [PreviousIcons & Images](https://developers.raycast.com/api-reference/user-interface/icons-and-images) [NextRaycast Window & Search Bar](https://developers.raycast.com/api-reference/window-and-search-bar) Last updated 1 year ago * [API Reference](https://developers.raycast.com/api-reference/user-interface/navigation#api-reference) * [useNavigation](https://developers.raycast.com/api-reference/user-interface/navigation#usenavigation) * [Types](https://developers.raycast.com/api-reference/user-interface/navigation#types) * [Navigation](https://developers.raycast.com/api-reference/user-interface/navigation#navigation) --- # Getting a Google client ID | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/oauth/getting-google-client-id.md) . Follow these steps to get a Google client ID: [](https://developers.raycast.com/utilities/oauth/getting-google-client-id#step-1-access-google-cloud-console) Step 1: Access Google Cloud Console ------------------------------------------------------------------------------------------------------------------------------------------------------- Navigate to the [Google Cloud Console](https://console.developers.google.com/apis/credentials) . [](https://developers.raycast.com/utilities/oauth/getting-google-client-id#step-2-create-a-project-if-needed) Step 2: Create a Project (if needed) ------------------------------------------------------------------------------------------------------------------------------------------------------- 1. Click **Create Project**. 2. Provide a **Project Name**. 3. Select an optional **Organization**. 4. Click **Create**. [](https://developers.raycast.com/utilities/oauth/getting-google-client-id#step-3-enable-required-apis) Step 3: Enable Required APIs ----------------------------------------------------------------------------------------------------------------------------------------- 1. Go to **Enabled APIs & services**. 2. Click **ENABLE APIS AND SERVICES**. 3. Search for and enable the required API (e.g., Google Drive API). [](https://developers.raycast.com/utilities/oauth/getting-google-client-id#step-4-configure-oauth-consent-screen) Step 4: Configure OAuth Consent Screen ------------------------------------------------------------------------------------------------------------------------------------------------------------- 1. Click on **OAuth consent screen**. 2. Choose **Internal** or **External** (choose **External** if you intend to publish the extension in the Raycast store). 3. Enter these details: * **App name**: Raycast (Your Extension Name) * **User support email**: your-email@example.com * **Logo**: Paste Raycast's logo over there ([Link to Raycast logo](https://raycastapp.notion.site/Raycast-Press-Kit-ce1ccf8306b14ac8b8d47b3276bf34e0#29cbc2f3841444fdbdcb1fdff2ea2abf) ) * **Application home page**: https://www.raycast.com * **Application privacy policy link**: https://www.raycast.com/privacy * **Application terms of service link**: https://www.raycast.com/terms-of-service * **Authorized domains**: Click **ADD DOMAIN** then add `raycast.com` * **Developer contact**: your-email@example.com 4. Add the necessary scopes for your app (visit the [Google OAuth scopes docs](https://developers.google.com/identity/protocols/oauth2/scopes) if you manually need to add scopes) 5. Add your own email as a test user and others if needed 6. Review and go back to the dashboard [](https://developers.raycast.com/utilities/oauth/getting-google-client-id#step-5-create-an-oauth-client-id) Step 5: Create an OAuth Client ID --------------------------------------------------------------------------------------------------------------------------------------------------- 1. Go to **Credentials**, click **CREATE CREDENTIALS**, then **OAuth client ID** 2. Choose **iOS** as the application type 3. Set the **Bundle ID** to `com.raycast`. 4. Copy your **Client ID** [](https://developers.raycast.com/utilities/oauth/getting-google-client-id#step-6-use-your-new-client-id) Step 6: Use Your New Client ID πŸŽ‰ ------------------------------------------------------------------------------------------------------------------------------------------------ You'll need to publish the app in the **OAuth consent screen** so that everyone can use it (and not only test users). The process can be more or less complex depending on whether you use sensitive or restrictive scopes. [PreviousgetAccessToken](https://developers.raycast.com/utilities/oauth/getaccesstoken) [NextReact hooks](https://developers.raycast.com/utilities/react-hooks) Last updated 2 years ago * [Step 1: Access Google Cloud Console](https://developers.raycast.com/utilities/oauth/getting-google-client-id#step-1-access-google-cloud-console) * [Step 2: Create a Project (if needed)](https://developers.raycast.com/utilities/oauth/getting-google-client-id#step-2-create-a-project-if-needed) * [Step 3: Enable Required APIs](https://developers.raycast.com/utilities/oauth/getting-google-client-id#step-3-enable-required-apis) * [Step 4: Configure OAuth Consent Screen](https://developers.raycast.com/utilities/oauth/getting-google-client-id#step-4-configure-oauth-consent-screen) * [Step 5: Create an OAuth Client ID](https://developers.raycast.com/utilities/oauth/getting-google-client-id#step-5-create-an-oauth-client-id) * [Step 6: Use Your New Client ID πŸŽ‰](https://developers.raycast.com/utilities/oauth/getting-google-client-id#step-6-use-your-new-client-id) --- # withAccessToken | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/oauth/withaccesstoken.md) . Higher-order function fetching an authorization token to then access it. This makes it easier to handle OAuth in your different commands whether they're `view` commands, `no-view` commands, or `menu-bar` commands. [](https://developers.raycast.com/utilities/oauth/withaccesstoken#signature) Signature ------------------------------------------------------------------------------------------- Copy function withAccessToken( options: WithAccessTokenParameters, ): >( fnOrComponent: U, ) => U extends (props: T) => Promise | void ? Promise : React.FunctionComponent; ### [](https://developers.raycast.com/utilities/oauth/withaccesstoken#arguments) Arguments `options` is an object containing: * `options.authorize`: a function that initiates the OAuth token retrieval process. It returns a promise that resolves to an access token. * `options.personalAccessToken`: an optional string that represents an already obtained personal access token. When `options.personalAccessToken` is provided, it uses that token. Otherwise, it calls `options.authorize` to fetch an OAuth token asynchronously. * `options.client`: an optional instance of a PKCE Client that you can create using Raycast API. This client is used to return the `idToken` as part of the `onAuthorize` callback below. * `options.onAuthorize`: an optional callback function that is called once the user has been properly logged in through OAuth. This function is called with the `token`, its type (`oauth` if it comes from an OAuth flow or `personal` if it's a personal access token), and `idToken` if it's returned from `options.client`'s initial token set. ### [](https://developers.raycast.com/utilities/oauth/withaccesstoken#return) Return Returns the wrapped component if used in a `view` command or the wrapped function if used in a `no-view` command. Note that the access token isn't injected into the wrapped component props. Instead, it's been set as a global variable that you can get with [getAccessToken](https://developers.raycast.com/utilities/oauth/getaccesstoken) . [](https://developers.raycast.com/utilities/oauth/withaccesstoken#example) Example --------------------------------------------------------------------------------------- view.tsx no-view.tsx onAuthorize.tsx [](https://developers.raycast.com/utilities/oauth/withaccesstoken#types) Types ----------------------------------------------------------------------------------- ### [](https://developers.raycast.com/utilities/oauth/withaccesstoken#withaccesstokenparameters) WithAccessTokenParameters ### [](https://developers.raycast.com/utilities/oauth/withaccesstoken#withaccesstokencomponentorfn) WithAccessTokenComponentOrFn [PreviousOAuthService](https://developers.raycast.com/utilities/oauth/oauthservice) [NextgetAccessToken](https://developers.raycast.com/utilities/oauth/getaccesstoken) Last updated 2 years ago * [Signature](https://developers.raycast.com/utilities/oauth/withaccesstoken#signature) * [Arguments](https://developers.raycast.com/utilities/oauth/withaccesstoken#arguments) * [Return](https://developers.raycast.com/utilities/oauth/withaccesstoken#return) * [Example](https://developers.raycast.com/utilities/oauth/withaccesstoken#example) * [Types](https://developers.raycast.com/utilities/oauth/withaccesstoken#types) * [WithAccessTokenParameters](https://developers.raycast.com/utilities/oauth/withaccesstoken#withaccesstokenparameters) * [WithAccessTokenComponentOrFn](https://developers.raycast.com/utilities/oauth/withaccesstoken#withaccesstokencomponentorfn) Copy import { List } from "@raycast/api"; import { withAccessToken } from "@raycast/utils"; import { authorize } from "./oauth"; function AuthorizedComponent(props) { return; // ... } export default withAccessToken({ authorize })(AuthorizedComponent); Copy import { showHUD } from "@raycast/api"; import { withAccessToken } from "@raycast/utils"; import { authorize } from "./oauth"; async function AuthorizedCommand() { await showHUD("Authorized"); } export default withAccessToken({ authorize })(AuthorizedCommand); Copy import { OAuthService } from "@raycast/utils"; import { LinearClient, LinearGraphQLClient } from "@linear/sdk"; let linearClient: LinearClient | null = null; const linear = OAuthService.linear({ scope: "read write", onAuthorize({ token }) { linearClient = new LinearClient({ accessToken: token }); }, }); function MyIssues() { return; // ... } export default withAccessToken(linear)(View); Copy type OAuthType = "oauth" | "personal"; type OnAuthorizeParams = { token: string; type: OAuthType; idToken: string | null; // only present if `options.client` has been provided }; type WithAccessTokenParameters = { client?: OAuth.PKCEClient; authorize: () => Promise; personalAccessToken?: string; onAuthorize?: (params: OnAuthorizeParams) => void; }; Copy type WithAccessTokenComponentOrFn = ((params: T) => Promise | void) | React.ComponentType; --- # Templates | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/information/developer-tools/templates.md) . Raycast provides a variety of templates to kickstart your extension. Raycast provides 3 types of templates: * **Commands:** These are templates for [commands](https://developers.raycast.com/information/terminology) . * **Tools:** These are templates for [tools](https://developers.raycast.com/information/terminology#tool) . You can select a different one for each tool that you add to your extension. * **Extension Boilerplates:** These are fully built extensions designed to be tweaked by organizations for internal use. [](https://developers.raycast.com/information/developer-tools/templates#commands) Commands ----------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/information/developer-tools/templates#show-detail) Show Detail Renders a simple Hello World from a markdown string.[](https://developers.raycast.com/information/developer-tools/templates#renders-a-simple-hello-world-from-a-markdown-string) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-e9490e58b081fe70c0c380534a452f981ed4d786%252Fdetail-template.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=fc4ba527&sv=2) Detail Template Render See the [API Reference](https://developers.raycast.com/api-reference/user-interface/detail) for more information about customization. ### [](https://developers.raycast.com/information/developer-tools/templates#submit-form) Submit Form Renders a form that showcases all available form elements.[](https://developers.raycast.com/information/developer-tools/templates#renders-a-form-that-showcases-all-available-form-elements) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-ee2d5d4c3fa780b7f14309bf826073e9dde9a96e%252Fform-template.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=b4a2be03&sv=2) Submit Form Template Render See the [API Reference](https://developers.raycast.com/api-reference/user-interface/form) for more information about customization. ### [](https://developers.raycast.com/information/developer-tools/templates#show-grid) Show Grid Renders a grid of Icons available from Raycast.[](https://developers.raycast.com/information/developer-tools/templates#renders-a-grid-of-icons-available-from-raycast) Defaults to a large grid, but provides a selection menu to change the size. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-585a703929e53a7f7f995ed2b6bf8e0a48f04faa%252Fgrid-template.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=efc08b2c&sv=2) Grid Template Render See the [API Reference](https://developers.raycast.com/api-reference/user-interface/grid) for more information about customization. See here for information about [Icons](https://developers.raycast.com/api-reference/user-interface/icons-and-images) . ### [](https://developers.raycast.com/information/developer-tools/templates#show-list-and-detail) Show List and Detail Renders a list of options. When an option is selected, a Detail view is displayed.[](https://developers.raycast.com/information/developer-tools/templates#renders-a-list-of-options.-when-an-option-is-selected-a-detail-view-is-displayed) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-2b379c00faa242c756f1a2aaad0a054b1648f8d6%252Flist-detail-template.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=8a673874&sv=2) List and Detail Template Render See the [API Reference](https://developers.raycast.com/api-reference/user-interface/list) for more information about customization. ### [](https://developers.raycast.com/information/developer-tools/templates#menu-bar-extra) Menu Bar Extra Adds a simple Menu Bar Extra with a menu.[](https://developers.raycast.com/information/developer-tools/templates#adds-a-simple-menu-bar-extra-with-a-menu) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-7bd81f2bcee7918b6921e552dae157b7f9c21733%252Fmenu-bar-template.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=af27a6ab&sv=2) Menu Bar Extra Template Render See the [API Reference](https://developers.raycast.com/api-reference/menu-bar-commands) for more information about customization. ### [](https://developers.raycast.com/information/developer-tools/templates#run-script) Run Script A example of a no-view command which shows a simple [HUD](https://developers.raycast.com/api-reference/feedback/hud) . ### [](https://developers.raycast.com/information/developer-tools/templates#show-list) Show List Renders a static list with each entry containing an icon, title, subtitle, and accessory.[](https://developers.raycast.com/information/developer-tools/templates#renders-a-static-list-with-each-entry-containing-an-icon-title-subtitle-and-accessory) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-c15c646bcffee77a3945ebb25a79a7f03f0e6e2f%252Flist-template.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=15f75f72&sv=2) List Template Render See the [API Reference](https://developers.raycast.com/api-reference/user-interface/list) for more information about customization. ### [](https://developers.raycast.com/information/developer-tools/templates#show-typeahead-results) Show Typeahead Results Renders a dynamic and searchable list of NPM packages. The command fetches new items as the search is updated by the user.[](https://developers.raycast.com/information/developer-tools/templates#renders-a-dynamic-and-searchable-list-of-npm-packages.-the-command-fetches-new-items-as-the-search-i) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-10b73f930dab0d742e677811c13b0b0c0706260b%252Ftypeahead-results-template.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=73810c90&sv=2) Typeahead Results Template Render ### [](https://developers.raycast.com/information/developer-tools/templates#ai) AI Renders the output of an AI call in a Detail view.[](https://developers.raycast.com/information/developer-tools/templates#renders-the-output-of-an-ai-call-in-a-detail-view) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-8af8468d2f78f69d28e7da00ef75198fce867b3c%252Fai-template.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=5130c1c9&sv=2) AI Template Render [](https://developers.raycast.com/information/developer-tools/templates#tools) Tools ----------------------------------------------------------------------------------------- A simple tool which asks for confirmation before executing.[](https://developers.raycast.com/information/developer-tools/templates#a-simple-tool-which-asks-for-confirmation-before-executing) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-48fb942ab974ffd90cba6e3f0659fbd273a9a24f%252Ftool-with-confirmation-template.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=703fc6e&sv=2) Tool with Confirmation Template Render See the [API Reference](https://developers.raycast.com/api-reference/tool) for more information about customization. [](https://developers.raycast.com/information/developer-tools/templates#extension-boilerplates) Extension Boilerplates --------------------------------------------------------------------------------------------------------------------------- The Raycast Team has created high-quality templates to reinforce team experiences with the Raycast API. Run `npm init raycast-extension -t ` to get started with these extensions. All templates can be found on the [templates page](https://www.raycast.com/templates) . Specific instructions about customizing the template can be found on the relevant [template page](https://www.raycast.com/templates) . Simply customize the template as you see fit, then run `npm run publish` in the extension directory to allow your team to install the extension. [PreviousVS Code (community tool)](https://developers.raycast.com/information/developer-tools/vscode) [NextSecurity](https://developers.raycast.com/information/security) Last updated 1 year ago * [Commands](https://developers.raycast.com/information/developer-tools/templates#commands) * [Show Detail](https://developers.raycast.com/information/developer-tools/templates#show-detail) * [Submit Form](https://developers.raycast.com/information/developer-tools/templates#submit-form) * [Show Grid](https://developers.raycast.com/information/developer-tools/templates#show-grid) * [Show List and Detail](https://developers.raycast.com/information/developer-tools/templates#show-list-and-detail) * [Menu Bar Extra](https://developers.raycast.com/information/developer-tools/templates#menu-bar-extra) * [Run Script](https://developers.raycast.com/information/developer-tools/templates#run-script) * [Show List](https://developers.raycast.com/information/developer-tools/templates#show-list) * [Show Typeahead Results](https://developers.raycast.com/information/developer-tools/templates#show-typeahead-results) * [AI](https://developers.raycast.com/information/developer-tools/templates#ai) * [Tools](https://developers.raycast.com/information/developer-tools/templates#tools) * [Extension Boilerplates](https://developers.raycast.com/information/developer-tools/templates#extension-boilerplates) --- # Menu Bar Commands | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/menu-bar-commands.md) . The `MenuBarExtra` component can be used to create commands which populate the [extras](https://developer.apple.com/design/human-interface-guidelines/components/system-experiences/the-menu-bar#menu-bar-commands) section of macOS' menu bar. Menubar commands aren't available on Windows. [](https://developers.raycast.com/api-reference/menu-bar-commands#getting-started) Getting Started ------------------------------------------------------------------------------------------------------- If you don't have an extension yet, follow the [getting started](https://developers.raycast.com/basics/getting-started) guide and then return to this page. Now that your extension is ready, let's open its `package.json` file and add a new entry to its `commands` array, ensuring its `mode` property is set to `menu-bar`. For this guide, let's add the following: Copy { "name": "github-pull-requests", "title": "Pull Requests", "subtitle": "GitHub", "description": "See your GitHub pull requests at a glance", "mode": "menu-bar" }, Check out the [command properties entry](https://developers.raycast.com/information/manifest#command-properties) in the manifest file documentation for more detailed information on each of those properties. Create `github-pull-requests.tsx` in your extensions `src/` folder and add the following: Copy import { MenuBarExtra } from "@raycast/api"; export default function Command() { return ( { console.log("seen pull request clicked"); }} /> { console.log("unseen pull request clicked"); }} /> ); } If your development server is running, the command should appear in your root search, and running the command should result in the `GitHub` icon appearing in your menu bar. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-d11d9547c3a590b50f9beacaf2211ee0056e4372%252Fmenu-bar-command.gif%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=57188bab&sv=2) GitHub Pull Requests menu bar command macOS has the final say on whether a given menu bar extra is displayed. If you have a lot of items there, it is possible that the command we just ran doesn't show up. If that's the case, try to clear up some space in the menu bar, either by closing some of the items you don't need or by hiding them using [HiddenBar](https://github.com/dwarvesf/hidden) , [Bartender](https://www.macbartender.com/) , or similar apps. Of course, our pull request command wouldn't be of that much use if we had to tell it to update itself every single time. To add [background refresh](https://developers.raycast.com/information/lifecycle/background-refresh) to our command, we need to open the `package.json` file we modified earlier and add an `interval` key to the command configuration object: Your root search should look similar to: ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-25f5659825806f33bb7cb303da04680bdb29bcbf%252Fmenu-bar-activate-command.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=b736a1cf&sv=2) Menu Bar Command - Activate Background Refresh Running it once should activate it to: ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-8f655dafc225472ab9096af040de0243f651dfb3%252Fmenu-bar-refresh.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=e7f89e4a&sv=2) Menu Bar Command - Refresh [](https://developers.raycast.com/api-reference/menu-bar-commands#lifecycle) Lifecycle ------------------------------------------------------------------------------------------- Although `menu-bar` commands can result in items permanently showing up in the macOS menu bar, they are not long-lived processes. Instead, as with other commands, Raycast loads them into memory on demand, executes their code and then tries to unload them at the next convenient time. There are five distinct events that can result in a `menu-bar`'s item being placed in the menu bar, so let's walk through each one. ### [](https://developers.raycast.com/api-reference/menu-bar-commands#from-the-root-search) From the root search Same as any other commands, `menu-bar` commands can be run directly from Raycast's root search. Eventually, they may result in a new item showing up in your menu bar (if you have enough room and if the command returns a `MenuBarExtra`), or in a previous item disappearing, if the command returns `null`. In this case, Raycast will load your command code, execute it, wait for the `MenuBarExtra`'s `isLoading` prop to switch to `false`, and unload the command. If your command returns a `MenuBarExtra`, it _must_ either not set `isLoading` - in which case Raycast will render and immediately unload the command, or set it to `true` while it's performing an async task (such as an API call) and then set it to `false` once it's done. Same as above, Raycast will load the command code, execute it, wait for `MenuBarExtra`'s `isLoading` prop to switch to `false`, and then unload the command. ### [](https://developers.raycast.com/api-reference/menu-bar-commands#at-a-set-interval) At a set interval If your `menu-bar` command also makes use of [background refresh](https://developers.raycast.com/information/lifecycle/background-refresh) _and_ it has background refresh activated, Raycast will run the command at set intervals. In your command, you can use `environment.launchType` to check whether it is launched in the background or by the user. To ease testing, commands configured to run in the background have an extra action in development mode: ![Menu Bar Command - Run in Background](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-5132ca095672c674588b6bc23879af43d9a303d9%252Fmenu-bar-run-in-background.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=cfe7a96c&sv=2) ### [](https://developers.raycast.com/api-reference/menu-bar-commands#when-the-user-clicks-the-commands-icon-title-in-the-menu-bar) When the user clicks the command's icon / title in the menu bar One of the bigger differences to `view` or `no-view` commands is that `menu-bar` commands have an additional entry point: when the user clicks their item in the menu bar. If the item has a menu (i.e. `MenuBarExtra` provides at least one child), Raycast will load the command code, execute it and keep it in memory while the menu is open. When the menu closes (either by the user clicking outside, or by clicking a `MenuBarExtra.Item`), the command is then unloaded. ### [](https://developers.raycast.com/api-reference/menu-bar-commands#when-raycast-is-restarted) When Raycast is restarted This case assumes that your command has run at least once, resulting in an item being placed in the menu bar. If that's the case, quitting and starting Raycast again should put the same item in your menu bar. However, that item will be restored from Raycast's database - _not_ by loading and executing the command. ### [](https://developers.raycast.com/api-reference/menu-bar-commands#when-a-menu-bar-command-is-re-enabled-in-preferences) When a menu bar command is re-enabled in preferences This case should work the same as when Raycast is restarted. [](https://developers.raycast.com/api-reference/menu-bar-commands#best-practices) Best practices ----------------------------------------------------------------------------------------------------- * make generous use of the [Cache API](https://developers.raycast.com/api-reference/cache) and our [Utilities](https://developers.raycast.com/utilities/getting-started) in order to provide quick feedback and ensure action handlers work as expected * make sure you set `isLoading` to false when your command finishes executing * avoid setting long titles in `MenuBarExtra`, `MenuBarExtra.Submenu` or `MenuBarExtra.Item` * don't put identical `MenuBarExtra.Item`s at the same level (direct children of `MenuBarExtra` or in the same `Submenu`) as their `onAction` handlers will not be executed correctly [](https://developers.raycast.com/api-reference/menu-bar-commands#api-reference) API Reference --------------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/menu-bar-commands#menubarextra) MenuBarExtra Adds an item to the menu bar, optionally with a menu attached in case its `children` prop is non-empty. `menu-bar` commands don't always need to return a `MenuBarExtra`. Sometimes it makes sense to remove an item from the menu bar, in which case you can write your command logic to return `null` instead. #### [](https://developers.raycast.com/api-reference/menu-bar-commands#example) Example #### [](https://developers.raycast.com/api-reference/menu-bar-commands#props) Props Prop Description Type Default children `MenuBarExtra.Item`s, `MenuBarExtra.Submenu`s, `MenuBarExtra.Separator` or a mix of either. `React.ReactNode` \- icon The icon that is displayed in the menu bar. [`Image.ImageLike`](https://developers.raycast.com/api-reference/user-interface/icons-and-images#image.imagelike) \- isLoading Indicates to Raycast that it should not unload the command, as it is still executing. If you set make use of `isLoading`, you need to make sure you set it to `false` at the end of the task you are executing (such as an API call), so Raycast can then unload the command. `boolean` \- title The string that is displayed in the menu bar. `string` \- tooltip A tooltip to display when the cursor hovers the item in the menu bar. `string` \- ### [](https://developers.raycast.com/api-reference/menu-bar-commands#menubarextra.item) MenuBarExtra.Item An item in the [MenuBarExtra](https://developers.raycast.com/api-reference/menu-bar-commands#menubarextra) or in a [MenuBarExtra.Submenu](https://developers.raycast.com/api-reference/menu-bar-commands#menubarextra.submenu) . #### [](https://developers.raycast.com/api-reference/menu-bar-commands#example-1) Example ItemWithTitle.tsx ItemWithTitleAndIcon.tsx ItemWithAction.tsx ItemWithAlternate.tsx An item that only provides a `title` prop will be rendered as disabled. Use this to create section titles. Similarly, an item that provides a `title` and an `icon` prop will also be rendered as disabled. An item that provides an `onAction` prop alongside `title` (and optionally `icon`) will _not_ be rendered as disabled. When users click this item in the menu bar, the action handler will be executed. If an item provides another `MenuBarEtra.Item` via its `alternate`, prop, the second item will be shown then the user presses the βŒ₯ (opt) key. There are a few limitation: 1. The `alternate` item may not have a custom shortcut. Instead, it will inherit its parent's shortcut, with the addition of βŒ₯ (opt) as a modifier. 2. The `alternate` item may not also specify an alternate. 3. A parent item that provides an `alternate` may not use βŒ₯ (opt) as a modifier. #### [](https://developers.raycast.com/api-reference/menu-bar-commands#props-1) Props Prop Description Type Default title\* The main title displayed for this item. `string` \- alternate A MenuBarExtra.Item to be displayed when a user presses the βŒ₯ (opt) key. `ReactElement<`[`MenuBarExtra.Item.Props`](https://developers.raycast.com/api-reference/menu-bar-commands#props) `, string>` \- icon An optional icon for this item. [`Image.ImageLike`](https://developers.raycast.com/api-reference/user-interface/icons-and-images#image.imagelike) \- onAction An action handler called when the user clicks the item. `(event:` [`MenuBarExtra.ActionEvent`](https://developers.raycast.com/api-reference/menu-bar-commands#menubarextra.actionevent) `) => void` \- shortcut A shortcut used to invoke this item when its parent menu is open. [`Keyboard.Shortcut`](https://developers.raycast.com/api-reference/keyboard#keyboard.shortcut) \- subtitle The subtitle displayed for this item. `string` \- tooltip A tooltip to display when the cursor hovers the item. `string` \- ### [](https://developers.raycast.com/api-reference/menu-bar-commands#menubarextra.submenu) MenuBarExtra.Submenu `MenuBarExtra.Submenu`s reveal their items when people interact with them. They're a good way to group items that naturally belong together, but keep in mind that submenus add complexity to your interface - so use them sparingly! #### [](https://developers.raycast.com/api-reference/menu-bar-commands#example-2) Example Bookmarks.tsx DisabledSubmenu.tsx Submenus with no children will show up as disabled. #### [](https://developers.raycast.com/api-reference/menu-bar-commands#props-2) Props Prop Description Type Default title\* The main title displayed for this submenu. `string` \- children `MenuBarExtra.Item`s, `MenuBarExtra.Submenu`s, `MenuBarExtra.Separator` or a mix of either. `React.ReactNode` \- icon An optional icon for this submenu. [`Image.ImageLike`](https://developers.raycast.com/api-reference/user-interface/icons-and-images#image.imagelike) \- ### [](https://developers.raycast.com/api-reference/menu-bar-commands#menubarextra.section) MenuBarExtra.Section An item to group related menu items. It has an optional title and a separator is added automatically between sections. #### [](https://developers.raycast.com/api-reference/menu-bar-commands#example-3) Example #### [](https://developers.raycast.com/api-reference/menu-bar-commands#props-3) Props Prop Description Type Default children The item elements of the section. `React.ReactNode` \- title Title displayed above the section `string` \- [](https://developers.raycast.com/api-reference/menu-bar-commands#types) Types ----------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/menu-bar-commands#menubarextra.actionevent) MenuBarExtra.ActionEvent An interface describing Action events in callbacks. #### [](https://developers.raycast.com/api-reference/menu-bar-commands#properties) Properties Property Description Type type\* A type of the action event \* `left-click` is a left mouse click on the MenuBarExtra.Item or a Keyboard.Shortcut \* `right-click` is a right mouse click on the MenuBarExtra.Item `"left-click"` or `"right-click"` #### [](https://developers.raycast.com/api-reference/menu-bar-commands#example-4) Example [PreviousKeyboard](https://developers.raycast.com/api-reference/keyboard) [NextOAuth](https://developers.raycast.com/api-reference/oauth) Last updated 13 days ago * [Getting Started](https://developers.raycast.com/api-reference/menu-bar-commands#getting-started) * [Lifecycle](https://developers.raycast.com/api-reference/menu-bar-commands#lifecycle) * [From the root search](https://developers.raycast.com/api-reference/menu-bar-commands#from-the-root-search) * [At a set interval](https://developers.raycast.com/api-reference/menu-bar-commands#at-a-set-interval) * [When the user clicks the command's icon / title in the menu bar](https://developers.raycast.com/api-reference/menu-bar-commands#when-the-user-clicks-the-commands-icon-title-in-the-menu-bar) * [When Raycast is restarted](https://developers.raycast.com/api-reference/menu-bar-commands#when-raycast-is-restarted) * [When a menu bar command is re-enabled in preferences](https://developers.raycast.com/api-reference/menu-bar-commands#when-a-menu-bar-command-is-re-enabled-in-preferences) * [Best practices](https://developers.raycast.com/api-reference/menu-bar-commands#best-practices) * [API Reference](https://developers.raycast.com/api-reference/menu-bar-commands#api-reference) * [MenuBarExtra](https://developers.raycast.com/api-reference/menu-bar-commands#menubarextra) * [MenuBarExtra.Item](https://developers.raycast.com/api-reference/menu-bar-commands#menubarextra.item) * [MenuBarExtra.Submenu](https://developers.raycast.com/api-reference/menu-bar-commands#menubarextra.submenu) * [MenuBarExtra.Section](https://developers.raycast.com/api-reference/menu-bar-commands#menubarextra.section) * [Types](https://developers.raycast.com/api-reference/menu-bar-commands#types) * [MenuBarExtra.ActionEvent](https://developers.raycast.com/api-reference/menu-bar-commands#menubarextra.actionevent) Copy { "name": "github-pull-requests", "title": "Pull Requests", "subtitle": "GitHub", "description": "See your GitHub pull requests at a glance", "mode": "menu-bar", "interval": "5m" } Copy import { Icon, MenuBarExtra, open } from "@raycast/api"; const data = { archivedBookmarks: [{ name: "Google Search", url: "www.google.com" }], newBookmarks: [{ name: "Raycast", url: "www.raycast.com" }], }; export default function Command() { return ( {data?.newBookmarks.map((bookmark) => ( open(bookmark.url)} /> ))} {data?.archivedBookmarks.map((bookmark) => ( open(bookmark.url)} /> ))} ); } Copy import { Icon, MenuBarExtra } from "@raycast/api"; export default function Command() { return ( ); } Copy import { Icon, MenuBarExtra } from "@raycast/api"; export default function Command() { return ( ); } Copy import { Icon, MenuBarExtra, open } from "@raycast/api"; export default function Command() { return ( open("https://raycast.com")} /> ); } Copy import { Icon, MenuBarExtra, open } from "@raycast/api"; export default function Command() { return ( open("https://raycast.com")} alternate={ open("https://raycast.com/store")} /> } /> ); } Copy import { Icon, MenuBarExtra, open } from "@raycast/api"; export default function Command() { return ( open("https://raycast.com")} /> open("https://github.com/pulls")} /> open("https://github.com/issues")} /> ); } Copy import { Icon, MenuBarExtra, open } from "@raycast/api"; export default function Command() { return ( ); } Copy import { Icon, MenuBarExtra, open } from "@raycast/api"; const data = { archivedBookmarks: [{ name: "Google Search", url: "www.google.com" }], newBookmarks: [{ name: "Raycast", url: "www.raycast.com" }], }; export default function Command() { return ( {data?.newBookmarks.map((bookmark) => ( open(bookmark.url)} /> ))} {data?.archivedBookmarks.map((bookmark) => ( open(bookmark.url)} /> ))} ); } Copy import { MenuBarExtra } from "@raycast/api"; export default function Command() { return ( console.log("Action Event Type", event.type)} /> ); } --- # Action Panel | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/user-interface/action-panel.md) . ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-25a03b5271959426230e724a733f30e7597dd1bf%252Faction-panel.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=fed1aeb0&sv=2) [](https://developers.raycast.com/api-reference/user-interface/action-panel#api-reference) API Reference ------------------------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel) ActionPanel Exposes a list of [actions](https://developers.raycast.com/api-reference/user-interface/actions) that can be performed by the user. Often items are context-aware, e.g., based on the selected list item. Actions can be grouped into semantic sections and can have keyboard shortcuts assigned. The first and second action become the primary and secondary action. They automatically get the default keyboard shortcuts assigned. In [List](https://developers.raycast.com/api-reference/user-interface/list) , [Grid](https://developers.raycast.com/api-reference/user-interface/grid) , and [Detail](https://developers.raycast.com/api-reference/user-interface/detail) , this is `↡` for the primary and `⌘` `↡` for the secondary action. In [Form](https://developers.raycast.com/api-reference/user-interface/form) it's `⌘` `↡` for the primary and `⌘` `⇧` `↡` for the secondary. Keep in mind that while you can specify an alternative shortcut for the primary and secondary actions, it won't be displayed in the Action Panel. #### [](https://developers.raycast.com/api-reference/user-interface/action-panel#example) Example #### [](https://developers.raycast.com/api-reference/user-interface/action-panel#props) Props Prop Description Type Default children Sections or Actions. If Action elements are specified, a default section is automatically created. [`ActionPanel.Children`](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.children) \- title The title displayed at the top of the panel `string` \- ### [](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.section) ActionPanel.Section A group of visually separated items. Use sections when the [ActionPanel](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel) contains a lot of actions to help guide the user to related actions. For example, create a section for all copy actions. #### [](https://developers.raycast.com/api-reference/user-interface/action-panel#example-1) Example #### [](https://developers.raycast.com/api-reference/user-interface/action-panel#props-1) Props Prop Description Type Default children The item elements of the section. [`ActionPanel.Section.Children`](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.section.children) \- title Title displayed above the section `string` \- ### [](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.submenu) ActionPanel.Submenu A very specific action that replaces the current [ActionPanel](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel) with its children when selected. This is handy when an action needs to select from a range of options. For example, to add a label to a GitHub pull request or an assignee to a todo. #### [](https://developers.raycast.com/api-reference/user-interface/action-panel#example-2) Example #### [](https://developers.raycast.com/api-reference/user-interface/action-panel#props-2) Props Prop Description Type Default title\* The title displayed for submenu. `string` \- autoFocus Indicates whether the ActionPanel.Submenu should be focused automatically when the parent ActionPanel (or Actionpanel.Submenu) opens. `boolean` \- children Items of the submenu. [`ActionPanel.Submenu.Children`](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.submenu.children) \- filtering Toggles Raycast filtering. When `true`, Raycast will use the query in the search bar to filter the items. When `false`, the extension needs to take care of the filtering. You can further define how native filtering orders sections by setting an object with a `keepSectionOrder` property: When `true`, ensures that Raycast filtering maintains the section order as defined in the extension. When `false`, filtering may change the section order depending on the ranking values of items. `boolean` or `{ keepSectionOrder: boolean }` \- icon The icon displayed for the submenu. [`Image.ImageLike`](https://developers.raycast.com/api-reference/user-interface/icons-and-images#image.imagelike) \- isLoading Indicates whether a loading indicator should be shown or hidden next to the search bar `boolean` \- onOpen Callback that is triggered when the Submenu is opened. This callback can be used to fetch its content lazily: `js function LazySubmenu() { const [content, setContent] = useState(null) return ( fetchSubmenuContent().then(setContent)}> {content} ) }` `() => void` \- onSearchTextChange Callback triggered when the search bar text changes. `(text: string) => void` \- shortcut The keyboard shortcut for the submenu. [`Keyboard.Shortcut`](https://developers.raycast.com/api-reference/keyboard#keyboard.shortcut) \- throttle Defines whether the `onSearchTextChange` handler will be triggered on every keyboard press or with a delay for throttling the events. Recommended to set to `true` when using custom filtering logic with asynchronous operations (e.g. network requests). `boolean` \- [](https://developers.raycast.com/api-reference/user-interface/action-panel#types) Types --------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.children) ActionPanel.Children Supported children for the [ActionPanel](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel) component. ### [](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.section.children) ActionPanel.Section.Children Supported children for the [ActionPanel.Section](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.section) component. ### [](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.submenu.children) ActionPanel.Submenu.Children Supported children for the [ActionPanel.Submenu](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.submenu) component. [PreviousUser Interface](https://developers.raycast.com/api-reference/user-interface) [NextActions](https://developers.raycast.com/api-reference/user-interface/actions) Last updated 1 year ago * [API Reference](https://developers.raycast.com/api-reference/user-interface/action-panel#api-reference) * [ActionPanel](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel) * [ActionPanel.Section](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.section) * [ActionPanel.Submenu](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.submenu) * [Types](https://developers.raycast.com/api-reference/user-interface/action-panel#types) * [ActionPanel.Children](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.children) * [ActionPanel.Section.Children](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.section.children) * [ActionPanel.Submenu.Children](https://developers.raycast.com/api-reference/user-interface/action-panel#actionpanel.submenu.children) Copy import { ActionPanel, Action, List } from "@raycast/api"; export default function Command() { return ( } /> ); } Copy import { ActionPanel, Action, List } from "@raycast/api"; export default function Command() { return ( console.log("Close PR #1")} /> } /> ); } Copy import { Action, ActionPanel, Color, Icon, List } from "@raycast/api"; export default function Command() { return ( console.log("Add bug label")} /> console.log("Add enhancement label")} /> console.log("Add help wanted label")} /> } /> ); } Copy ActionPanel.Children: ActionPanel.Section | ActionPanel.Section[] | ActionPanel.Section.Children | null Copy ActionPanel.Section.Children: Action | Action[] | ReactElement | ReactElement[] | null Copy ActionPanel.Children: ActionPanel.Section | ActionPanel.Section[] | ActionPanel.Section.Children | null --- # FAQ | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/misc/faq.md) . What's the difference between [script commands](https://github.com/raycast/script-commands) and extensions?[](https://developers.raycast.com/misc/faq#whats-the-difference-between-script-commands-and-extensions) Script commands were the first way to extend Raycast. They are a simple way to execute a shell script and show some limited output in Raycast. Extensions are our next iteration to extend Raycast. While scripts can be written in pretty much any scripting language, extensions are written in TypeScript. They can show rich user interfaces like lists and forms but can also be "headless" and just run a simple script. Extensions can be shared with our community via our Store. This makes them easy to discover and use for not so technical folks that don't have homebrew or other shell integrations on their Mac. Why can I not use `react-dom`?[](https://developers.raycast.com/misc/faq#why-can-i-not-use-react-dom) Even though you write JS/TS code, everything is rendered natively in Raycast. There isn't any HTML or CSS involved. Therefore you don't need the DOM-specific methods that the `react-dom` package provides. Instead, we implemented a custom [reconciler](https://reactjs.org/docs/reconciliation.html) that converts your React component tree to a render tree that Raycast understands. The render tree is used natively to construct a view hierarchy that is backed by [Apple's AppKit](https://developer.apple.com/documentation/appkit/) . This is similar to how [React Native](https://reactnative.dev/) works. Can I import ESM packages in my extension?[](https://developers.raycast.com/misc/faq#can-i-import-esm-packages-in-my-extension) Yes, but you need to convert your extension to ESM. Quick steps: * Make sure you are using TypeScript 4.7 or later. * Add `"type": "module"` to your package.json. * Add `"module": "node16", "moduleResolution": "node16"` to your tsconfig.json. * Use only full relative file paths for imports: `import x from '.';` β†’ `import x from './index.js';`. * Remove `namespace` usage and use `export` instead. * Use the [`node:` protocol](https://nodejs.org/api/esm.html#esm_node_imports) for Node.js built-in imports. * **You must use a** `**.js**` **extension in relative imports even though you're importing** `**.ts**` **files.** [Previousv1.59.0](https://developers.raycast.com/misc/migration/v1.59.0) Last updated 2 years ago --- # v1.42.0 | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/misc/migration/v1.42.0.md) . This version changed the `enableFiltering` option of `Grid` to `filtering`. The `enableFiltering` prop still work, but is now marked as deprecated and may be removed in a future version. You will get helpful hints in your code editor to migrate your extension, and as usual we provide automated [migrations](https://developers.raycast.com/misc/migration) to help with the transition. To migrate your extension manually, you need to ensure that all `Grid` that specify `enableFiltering` are updated as follows: Copy ... // becomes ... [Previousv1.37.0](https://developers.raycast.com/misc/migration/v1.37.0) [Nextv1.48.8](https://developers.raycast.com/misc/migration/v1.48.8) Last updated 2 years ago --- # v1.51.0 | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/misc/migration/v1.51.0.md) . This version changed `environment.theme` to `environment.appearance`. `environment.theme` still works, but is now marked as deprecated and may be removed in a future version. You will get helpful hints in your code editor to migrate your extension, and as usual we provide automated [migrations](https://developers.raycast.com/misc/migration) to help with the transition. To migrate your extension manually, you need to ensure that all `environment.theme` are updated to `environment.appearance`. [Previousv1.50.0](https://developers.raycast.com/misc/migration/v1.50.0) [Nextv1.59.0](https://developers.raycast.com/misc/migration/v1.59.0) Last updated 2 years ago --- # Migration | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/misc/migration.md) . This section contains guides to help migrate your extension to a newer version of the API. [](https://developers.raycast.com/misc/migration#how-to-automatically-migrate-your-extensions) How to automatically migrate your extensions ------------------------------------------------------------------------------------------------------------------------------------------------ Whenever possible, we provide tools to automate the migration to a newer version of the API using [codemods](https://github.com/facebook/jscodeshift) . To run the codemods, run the following command in your extension directory: Copy npx ray migrate or Copy npx @raycast/migration@latest . It will detect the version of the API you were previously using and apply all the migrations that have been available since. After running it, do go through the updated files and make sure nothing is broken - there are always edge cases. [PreviousChangelog](https://developers.raycast.com/misc/changelog) [Nextv1.28.0](https://developers.raycast.com/misc/migration/v1.28.0) Last updated 3 years ago --- # Colors | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/user-interface/colors.md) . Anywhere you can pass a color in a component prop, you can pass either: * A standard [Color](https://developers.raycast.com/api-reference/user-interface/colors#color) * A [Dynamic](https://developers.raycast.com/api-reference/user-interface/colors#color.dynamic) Color * A [Raw](https://developers.raycast.com/api-reference/user-interface/colors#color.raw) Color [](https://developers.raycast.com/api-reference/user-interface/colors#api-reference) API Reference ------------------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/user-interface/colors#color) Color The standard colors. Use those colors for consistency. The colors automatically adapt to the Raycast theme (light or dark). #### [](https://developers.raycast.com/api-reference/user-interface/colors#example) Example Copy import { Color, Icon, List } from "@raycast/api"; export default function Command() { return ( ); } #### [](https://developers.raycast.com/api-reference/user-interface/colors#enumeration-members) Enumeration members Name Dark Theme Light Theme Blue ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-bb792f0278bbeea127bab32134a0addabe1f471d%252Fcolor-dark-blue.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=67e64adc&sv=2) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-b5fd11b78553af9231fec2bbd2065fa5b21daccd%252Fcolor-blue.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=f74e7c4a&sv=2) Green ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-1f26f61f56df07565cd4749355f553c998856c75%252Fcolor-dark-green.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=7dedf098&sv=2) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-0ecfe804320264a9ea87283aaa994930f7cb4d7d%252Fcolor-green.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=8db665e1&sv=2) Magenta ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-460fbc6e16fa66a017a31462d181e1b7db1299f1%252Fcolor-dark-magenta.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=540c420d&sv=2) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-aab0de01b6ee3f98eedd291af31708cc27c1bceb%252Fcolor-magenta.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=e4d37226&sv=2) Orange ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-5c867edbcb01e9fb71ddbfd0351ec7e19cadbec2%252Fcolor-dark-orange.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=40cde93a&sv=2) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-a80e366e832757469108afcaddff62f3aeb1d3a0%252Fcolor-orange.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=e10f60f5&sv=2) Purple ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-6e5cba871d9c05aa374915445a220b40f3838aeb%252Fcolor-dark-purple.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=3c0790fb&sv=2) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-eb0b963fade8b81c5680524e646b95ebb223476e%252Fcolor-purple.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=e91d45f8&sv=2) Red ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-ffb7f9534f418f2c52ff9983abbb886df9496f9f%252Fcolor-dark-red.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=ddc3f788&sv=2) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-73815c38fa3cbc20735f01160de3d9172a277cb1%252Fcolor-red.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=b4651e20&sv=2) Yellow ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-970d9768755133d23b1e27ff90b72b78e4753bad%252Fcolor-dark-yellow.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=5ab8fefd&sv=2) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-656146171a1eb17d688bb5bc16eb442f955a6cf3%252Fcolor-yellow.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=c294b22e&sv=2) PrimaryText ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-46bb91f2a4e7d5a5ebe2b6e358560c6f5933ed47%252Fcolor-dark-primary-text.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=a7f7a6b2&sv=2) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-a2b368984466f481e372240d508588bb603f88bb%252Fcolor-primary-text.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=cb351666&sv=2) SecondaryText ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-eb8e7a97fd21d5853b9c40bc47634e4b8033585e%252Fcolor-dark-secondary-text.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=7f43a2a6&sv=2) ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-6302cb6111a94d075871bbc02b7d39b124eb70dd%252Fcolor-secondary-text.webp%3Falt%3Dmedia&width=300&dpr=3&quality=100&sign=e401b6d8&sv=2) [](https://developers.raycast.com/api-reference/user-interface/colors#types) Types --------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/user-interface/colors#color.colorlike) Color.ColorLike Union type for the supported color types. When using a [Raw Color](https://developers.raycast.com/api-reference/user-interface/colors#color.raw) , it will be adjusted to achieve high contrast with the Raycast user interface. To disable color adjustment, you need to switch to using a [Dynamic Color](https://developers.raycast.com/api-reference/user-interface/colors#color.dynamic) . However, we recommend leaving color adjustment on, unless your extension depends on exact color reproduction. #### [](https://developers.raycast.com/api-reference/user-interface/colors#example-1) Example ### [](https://developers.raycast.com/api-reference/user-interface/colors#color.dynamic) Color.Dynamic A dynamic color applies different colors depending on the active Raycast theme. When using a [Dynamic Color](https://developers.raycast.com/api-reference/user-interface/colors#color.dynamic) , it will be adjusted to achieve high contrast with the Raycast user interface. To disable color adjustment, you can set the `adjustContrast` property to `false`. However, we recommend leaving color adjustment on, unless your extension depends on exact color reproduction. #### [](https://developers.raycast.com/api-reference/user-interface/colors#example-2) Example #### [](https://developers.raycast.com/api-reference/user-interface/colors#properties) Properties Property Description Type dark\* The color which is used in dark theme. `string` light\* The color which is used in light theme. `string` adjustContrast Enables dynamic contrast adjustment for light and dark theme color. `boolean` ### [](https://developers.raycast.com/api-reference/user-interface/colors#color.raw) Color.Raw A color can also be a simple string. You can use any of the following color formats: * HEX, e.g `#FF0000` * Short HEX, e.g. `#F00` * RGBA, e.g. `rgb(255, 0, 0)` * RGBA Percentage, e.g. `rgb(255, 0, 0, 1.0)` * HSL, e.g. `hsla(200, 20%, 33%, 0.2)` * Keywords, e.g. `red` [PreviousGrid](https://developers.raycast.com/api-reference/user-interface/grid) [NextIcons & Images](https://developers.raycast.com/api-reference/user-interface/icons-and-images) Last updated 1 year ago * [API Reference](https://developers.raycast.com/api-reference/user-interface/colors#api-reference) * [Color](https://developers.raycast.com/api-reference/user-interface/colors#color) * [Types](https://developers.raycast.com/api-reference/user-interface/colors#types) * [Color.ColorLike](https://developers.raycast.com/api-reference/user-interface/colors#color.colorlike) * [Color.Dynamic](https://developers.raycast.com/api-reference/user-interface/colors#color.dynamic) * [Color.Raw](https://developers.raycast.com/api-reference/user-interface/colors#color.raw) Copy ColorLike: Color | Color.Dynamic | Color.Raw; Copy import { Color, Icon, List } from "@raycast/api"; export default function Command() { return ( ); } Copy import { Icon, List } from "@raycast/api"; export default function Command() { return ( ); } --- # v1.50.0 | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/misc/migration/v1.50.0.md) . This version introduces an automated generation of typescript definitions for the preferences and arguments of your extension's commands. After updating the API version, you will notice a new file at the root of the extension folder called `raycast-env.d.ts`. * You shouldn't add this file to git so you have to update your `.gitignore` file: Copy + raycast-env.d.ts * You have to tell TypeScript to pick up this file to get access to its type definitions. To do so, update the `tsconfig.json` file: Copy - "include": ["src/**/*"], + "include": ["src/**/*", "raycast-env.d.ts"], * You can now update your code to leverage the automated types: Copy ... - export default function Command(props: LaunchProps<{ arguments: { input: string } }>) { + export default function Command(props: LaunchProps<{ arguments: Arguments.CommandName }>) { ... ... - const prefs: { apiKey: string } = getPreferenceValues(); + const prefs: Preferences.CommandName = getPreferenceValues(); ... [Previousv1.48.8](https://developers.raycast.com/misc/migration/v1.48.8) [Nextv1.51.0](https://developers.raycast.com/misc/migration/v1.51.0) Last updated 3 years ago --- # React hooks | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/react-hooks.md) . [useCachedState](https://developers.raycast.com/utilities/react-hooks/usecachedstate) [usePromise](https://developers.raycast.com/utilities/react-hooks/usepromise) [useCachedPromise](https://developers.raycast.com/utilities/react-hooks/usecachedpromise) [useFetch](https://developers.raycast.com/utilities/react-hooks/usefetch) [useForm](https://developers.raycast.com/utilities/react-hooks/useform) [useExec](https://developers.raycast.com/utilities/react-hooks/useexec) [useSQL](https://developers.raycast.com/utilities/react-hooks/usesql) [useAI](https://developers.raycast.com/utilities/react-hooks/useai) [useFrecencySorting](https://developers.raycast.com/utilities/react-hooks/usefrecencysorting) [useStreamJSON](https://developers.raycast.com/utilities/react-hooks/usestreamjson) [useLocalStorage](https://developers.raycast.com/utilities/react-hooks/uselocalstorage) [PreviousGetting a Google client ID](https://developers.raycast.com/utilities/oauth/getting-google-client-id) [NextuseCachedState](https://developers.raycast.com/utilities/react-hooks/usecachedstate) Last updated 2 years ago --- # v1.31.0 | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/misc/migration/v1.31.0.md) . This version introduces support for multiple `` accessories via a new [`accessories` prop](https://developers.raycast.com/api-reference/user-interface/list#list.item.accessory) . The `accessoryTitle` and `accessoryIcon` props still work, but are now marked as deprecated and may be removed in a future version. You will get helpful hints in your code editor to migrate your extension, and as usual we provide automated [migrations](https://developers.raycast.com/misc/migration) to help with the transition. To migrate your extension manually, you need to ensure that all `List.Items` that specify `accessoryTitle` and/or `accessoryIcon` are updated as follows: [](https://developers.raycast.com/misc/migration/v1.31.0#list.item-with-accessorytitle) `List.Item` with `accessoryTitle` ------------------------------------------------------------------------------------------------------------------------------ Copy // becomes // becomes // becomes ( key: string, initialState?: T, config?: { cacheNamespace?: string; }, ): [T, (newState: T | ((prevState: T) => T)) => void]; ### [](https://developers.raycast.com/utilities/react-hooks/usecachedstate#arguments) Arguments * `key` is the unique identifier of the state. This can be used to share the state across components and/or commands (hooks using the same key will share the same state, eg. updating one will update the others). With a few options: * `initialState` is the initial value of the state if there aren't any in the Cache yet. * `config.cacheNamespace` is a string that can be used to namespace the key. [](https://developers.raycast.com/utilities/react-hooks/usecachedstate#example) Example -------------------------------------------------------------------------------------------- [PreviousReact hooks](https://developers.raycast.com/utilities/react-hooks) [NextusePromise](https://developers.raycast.com/utilities/react-hooks/usepromise) Last updated 2 years ago * [Signature](https://developers.raycast.com/utilities/react-hooks/usecachedstate#signature) * [Arguments](https://developers.raycast.com/utilities/react-hooks/usecachedstate#arguments) * [Example](https://developers.raycast.com/utilities/react-hooks/usecachedstate#example) Copy import { List, ActionPanel, Action } from "@raycast/api"; import { useCachedState } from "@raycast/utils"; export default function Command() { const [showDetails, setShowDetails] = useCachedState("show-details", false); return ( setShowDetails((x) => !x)} /> } > ... ); } --- # Detail | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/user-interface/detail.md) . ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-c2161bc51a61a09b4a7aea8a1ed6ab3f65ddd566%252Fdetail.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=3603f43b&sv=2) [](https://developers.raycast.com/api-reference/user-interface/detail#api-reference) API Reference ------------------------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/user-interface/detail#detail) Detail Renders a markdown ([CommonMark](https://commonmark.org/) ) string with an optional metadata panel. Typically used as a standalone view or when navigating from a [List](https://developers.raycast.com/api-reference/user-interface/list) . #### [](https://developers.raycast.com/api-reference/user-interface/detail#example) Example Render a markdown string Render an image from the assets directory #### [](https://developers.raycast.com/api-reference/user-interface/detail#props) Props Prop Description Type Default actions A reference to an ActionPanel. `React.ReactNode` \- isLoading Indicates whether a loading bar should be shown or hidden below the search bar `boolean` \- markdown The CommonMark string to be rendered. `string` \- metadata The `Detail.Metadata` to be rendered in the right side area `React.ReactNode` \- navigationTitle The main title for that view displayed in Raycast `string` \- You can specify custom image dimensions by adding a `raycast-width` and `raycast-height` query string to the markdown image. For example: `![Image Title](example.png?raycast-width=250&raycast-height=250)` You can also specify a tint color to apply to an markdown image by adding a `raycast-tint-color` query string. For example: `![Image Title](example.png?raycast-tintColor=blue)` You can now render [LaTeX](https://www.latex-project.org/) in the markdown. We support the following delimiters: * Inline math: `\(...\)` and `\begin{math}...\end{math}` * Display math: `\[...\]`, `$$...$$` and `\begin{equation}...\end{equation}` ### [](https://developers.raycast.com/api-reference/user-interface/detail#detail.metadata) Detail.Metadata A Metadata view that will be shown in the right-hand-side of the `Detail`. Use it to display additional structured data about the main content shown in the `Detail` view. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-2ff9dfb88c0b6358b14ffac00c3cff10697634d0%252Fdetail-metadata.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=eb3741c5&sv=2) Detail-metadata illustration #### [](https://developers.raycast.com/api-reference/user-interface/detail#example-1) Example #### [](https://developers.raycast.com/api-reference/user-interface/detail#props-1) Props Prop Description Type Default children\* The elements of the Metadata view. `React.ReactNode` \- ### [](https://developers.raycast.com/api-reference/user-interface/detail#detail.metadata.label) Detail.Metadata.Label A single value with an optional icon. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-6fe03ce7bad659317f81b002747ced317b60f20d%252Fdetail-metadata-label.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=9c8bb7e5&sv=2) Detail-metadata-label illustration #### [](https://developers.raycast.com/api-reference/user-interface/detail#example-2) Example #### [](https://developers.raycast.com/api-reference/user-interface/detail#props-2) Props Prop Description Type Default title\* The title of the item. `string` \- icon An icon to illustrate the value of the item. [`Image.ImageLike`](https://developers.raycast.com/api-reference/user-interface/icons-and-images#image.imagelike) \- text The text value of the item. Specifying `color` will display the text in the provided color. Defaults to Color.PrimaryText. `string` or `{ color?:` [`Color`](https://developers.raycast.com/api-reference/user-interface/colors#color) or `null; value: string }` \- ### [](https://developers.raycast.com/api-reference/user-interface/detail#detail.metadata.link) Detail.Metadata.Link An item to display a link. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-08ab8450b22fd002ea39ef5ff9a30f4f25f35861%252Fdetail-metadata-link.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=2d9cb233&sv=2) Detail-metadata-link illustration #### [](https://developers.raycast.com/api-reference/user-interface/detail#example-3) Example #### [](https://developers.raycast.com/api-reference/user-interface/detail#props-3) Props Prop Description Type Default target\* The target of the link. `string` \- text\* The text value of the item. `string` \- title\* The title shown above the item. `string` \- ### [](https://developers.raycast.com/api-reference/user-interface/detail#detail.metadata.taglist) Detail.Metadata.TagList A list of [`Tags`](https://developers.raycast.com/api-reference/user-interface/detail#detail.metadata.taglist.item) displayed in a row. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-6a0a834fb8f2b9b715b7c38797c3abb3c2f0a4c5%252Fdetail-metadata-taglist.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=d9c676d7&sv=2) Detail-metadata-taglist illustration #### [](https://developers.raycast.com/api-reference/user-interface/detail#example-4) Example #### [](https://developers.raycast.com/api-reference/user-interface/detail#props-4) Props Prop Description Type Default children\* The tags contained in the TagList. `React.ReactNode` \- title\* The title shown above the item. `string` \- ### [](https://developers.raycast.com/api-reference/user-interface/detail#detail.metadata.taglist.item) Detail.Metadata.TagList.Item A Tag in a `Detail.Metadata.TagList`. #### [](https://developers.raycast.com/api-reference/user-interface/detail#props-5) Props Prop Description Type Default color Changes the text color to the provided color and sets a transparent background with the same color. [`Color.ColorLike`](https://developers.raycast.com/api-reference/user-interface/colors#color.colorlike) \- icon The optional icon tag icon. Required if the tag has no text. [`Image.ImageLike`](https://developers.raycast.com/api-reference/user-interface/icons-and-images#image.imagelike) \- onAction Callback that is triggered when the item is clicked. `() => void` \- text The optional tag text. Required if the tag has no icon. `string` \- ### [](https://developers.raycast.com/api-reference/user-interface/detail#detail.metadata.separator) Detail.Metadata.Separator A metadata item that shows a separator line. Use it for grouping and visually separating metadata items. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-869ac40f387d81357bf011d3717ab975cc5645d9%252Fdetail-metadata-separator.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=50bfa94d&sv=2) [PreviousActions](https://developers.raycast.com/api-reference/user-interface/actions) [NextForm](https://developers.raycast.com/api-reference/user-interface/form) Last updated 13 days ago * [API Reference](https://developers.raycast.com/api-reference/user-interface/detail#api-reference) * [Detail](https://developers.raycast.com/api-reference/user-interface/detail#detail) * [Detail.Metadata](https://developers.raycast.com/api-reference/user-interface/detail#detail.metadata) * [Detail.Metadata.Label](https://developers.raycast.com/api-reference/user-interface/detail#detail.metadata.label) * [Detail.Metadata.Link](https://developers.raycast.com/api-reference/user-interface/detail#detail.metadata.link) * [Detail.Metadata.TagList](https://developers.raycast.com/api-reference/user-interface/detail#detail.metadata.taglist) * [Detail.Metadata.TagList.Item](https://developers.raycast.com/api-reference/user-interface/detail#detail.metadata.taglist.item) * [Detail.Metadata.Separator](https://developers.raycast.com/api-reference/user-interface/detail#detail.metadata.separator) Copy import { Detail } from "@raycast/api"; export default function Command() { return ; } Copy import { Detail } from "@raycast/api"; export default function Command() { return ; } Copy import { Detail } from "@raycast/api"; // Define markdown here to prevent unwanted indentation. const markdown = ` # Pikachu ![](https://assets.pokemon.com/assets/cms2/img/pokedex/full/025.png) Pikachu that can generate powerful electricity have cheek sacs that are extra soft and super stretchy. `; export default function Main() { return ( } /> ); } Copy import { Detail } from "@raycast/api"; // Define markdown here to prevent unwanted indentation. const markdown = ` # Pikachu ![](https://assets.pokemon.com/assets/cms2/img/pokedex/full/025.png) Pikachu that can generate powerful electricity have cheek sacs that are extra soft and super stretchy. `; export default function Main() { return ( } /> ); } Copy import { Detail } from "@raycast/api"; // Define markdown here to prevent unwanted indentation. const markdown = ` # Pikachu ![](https://assets.pokemon.com/assets/cms2/img/pokedex/full/025.png) Pikachu that can generate powerful electricity have cheek sacs that are extra soft and super stretchy. `; export default function Main() { return ( } /> ); } Copy import { Detail } from "@raycast/api"; // Define markdown here to prevent unwanted indentation. const markdown = ` # Pikachu ![](https://assets.pokemon.com/assets/cms2/img/pokedex/full/025.png) Pikachu that can generate powerful electricity have cheek sacs that are extra soft and super stretchy. `; export default function Main() { return ( } /> ); } Copy import { Detail } from "@raycast/api"; // Define markdown here to prevent unwanted indentation. const markdown = ` # Pikachu ![](https://assets.pokemon.com/assets/cms2/img/pokedex/full/025.png) Pikachu that can generate powerful electricity have cheek sacs that are extra soft and super stretchy. `; export default function Main() { return ( } /> ); } --- # v1.48.8 | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/misc/migration/v1.48.8.md) . This version introduces a new ESLint configuration file when creating new extensions with the `Create Extension` command. However, extensions prior to v1.48.8 still use the deprecated configuration. You can use `npx ray migrate` to use the new ESLint configuration and your `.eslintrc.json` file as well as your dependencies should be updated. If the migration didn't go well or if you defined the ESLint configuration in another place, please follow the steps below. First, install `@raycast/eslint-config` as part of your dev dependencies: Copy npm install @raycast/eslint-config --save-dev The previous default configuration looks like this: Copy { "root": true, "env": { "es2020": true, "node": true }, "parser": "@typescript-eslint/parser", "plugins": ["@typescript-eslint"], "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"] } With `@raycast/eslint-config`, you can replace the whole file with only the following: Copy { "root": true, "extends": [\ "@raycast"\ ] } If you added plugins, turned on/off rules, or anything else modifying the ESLint configuration, it's up to you to merge it with the new configuration. Finally, you can remove these ESLint dependencies: [Previousv1.42.0](https://developers.raycast.com/misc/migration/v1.42.0) [Nextv1.50.0](https://developers.raycast.com/misc/migration/v1.50.0) Last updated 3 years ago Copy npm uninstall @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-prettier --- # OAuthService | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/oauth/oauthservice.md) . The `OAuthService` class is designed to abstract the OAuth authorization process using the PKCE (Proof Key for Code Exchange) flow, simplifying the integration with various OAuth providers such as Asana, GitHub, and others. Use [OAuthServiceOptions](https://developers.raycast.com/utilities/oauth/oauthservice#oauthserviceoptions) to configure the `OAuthService` class. [](https://developers.raycast.com/utilities/oauth/oauthservice#example) Example ------------------------------------------------------------------------------------ Copy const client = new OAuth.PKCEClient({ redirectMethod: OAuth.RedirectMethod.Web, providerName: "GitHub", providerIcon: "extension_icon.png", providerId: "github", description: "Connect your GitHub account", }); const github = new OAuthService({ client, clientId: "7235fe8d42157f1f38c0", scope: "notifications repo read:org read:user read:project", authorizeUrl: "https://github.oauth.raycast.com/authorize", tokenUrl: "https://github.oauth.raycast.com/token", }); [](https://developers.raycast.com/utilities/oauth/oauthservice#signature) Signature ---------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/utilities/oauth/oauthservice#methods) Methods #### [](https://developers.raycast.com/utilities/oauth/oauthservice#authorize) `authorize` Initiates the OAuth authorization process or refreshes existing tokens if necessary. Returns a promise that resolves with the access token from the authorization flow. **Signature** **Example** ### [](https://developers.raycast.com/utilities/oauth/oauthservice#built-in-services) Built-in Services Some services are exposed as static properties in `OAuthService` to make it easy to authenticate with them: * [Asana](https://developers.raycast.com/utilities/oauth/oauthservice#asana) * [GitHub](https://developers.raycast.com/utilities/oauth/oauthservice#github) * [Google](https://developers.raycast.com/utilities/oauth/oauthservice#google) * [Jira](https://developers.raycast.com/utilities/oauth/oauthservice#jira) * [Linear](https://developers.raycast.com/utilities/oauth/oauthservice#linear) * [Slack](https://developers.raycast.com/utilities/oauth/oauthservice#slack) * [Zoom](https://developers.raycast.com/utilities/oauth/oauthservice#zoom) Asana, GitHub, Linear, and Slack already have an OAuth app configured by Raycast so that you can use them right of the box by specifing only the permission scopes. You are still free to create an OAuth app for them if you want. Google, Jira and Zoom don't have an OAuth app configured by Raycast so you'll have to create one if you want to use them. Use [ProviderOptions](https://developers.raycast.com/utilities/oauth/oauthservice#provideroptions) or [ProviderWithDefaultClientOptions](https://developers.raycast.com/utilities/oauth/oauthservice#providerwithdefaultclientoptions) to configure these built-in services. #### [](https://developers.raycast.com/utilities/oauth/oauthservice#asana) Asana **Signature** **Example** #### [](https://developers.raycast.com/utilities/oauth/oauthservice#github) GitHub **Signature** **Example** #### [](https://developers.raycast.com/utilities/oauth/oauthservice#google) Google Google has verification processes based on the required scopes for your extension. Therefore, you need to configure your own client for it. Creating your own Google client ID is more tedious than other processes, so we’ve created a page to assist you: [Getting a Google client ID](https://developers.raycast.com/utilities/oauth/getting-google-client-id) **Signature** **Example** #### [](https://developers.raycast.com/utilities/oauth/oauthservice#jira) Jira Jira requires scopes to be enabled manually in the OAuth app settings. Therefore, you need to configure your own client for it. **Signature** **Example** #### [](https://developers.raycast.com/utilities/oauth/oauthservice#linear) Linear **Signature** **Example** #### [](https://developers.raycast.com/utilities/oauth/oauthservice#slack) Slack **Signature** **Example** #### [](https://developers.raycast.com/utilities/oauth/oauthservice#zoom) Zoom Zoom requires scopes to be enabled manually in the OAuth app settings. Therefore, you need to configure your own client for it. **Signature** **Example** [](https://developers.raycast.com/utilities/oauth/oauthservice#types) Types -------------------------------------------------------------------------------- ### [](https://developers.raycast.com/utilities/oauth/oauthservice#oauthserviceoptions) OAuthServiceOptions Property Name Description Type client\* The PKCE Client defined using `OAuth.PKCEClient` from `@raycast/api` `OAuth.PKCEClient` clientId\* The app's client ID `string` scope\* The scope of the access requested from the provider `string` | `Array` authorizeUrl\* The URL to start the OAuth flow `string` tokenUrl\* The URL to exchange the authorization code for an access token `string` refreshTokenUrl The URL to refresh the access token if applicable `string` personalAccessToken A personal token if the provider supports it `string` onAuthorize A callback function that is called once the user has been properly logged in through OAuth when used with `withAccessToken` `string` extraParameters The extra parameters you may need for the authorization request `Record` bodyEncoding Specifies the format for sending the body of the request. `json` | `url-encoded` tokenResponseParser Some providers returns some non-standard token responses. Specifies how to parse the JSON response to get the access token `(response: unknown) => OAuth.TokenResponse` tokenRefreshResponseParser Some providers returns some non-standard refresh token responses. Specifies how to parse the JSON response to get the access token `(response: unknown) => OAuth.TokenResponse` ### [](https://developers.raycast.com/utilities/oauth/oauthservice#provideroptions) ProviderOptions Property Name Description Type clientId\* The app's client ID `string` scope\* The scope of the access requested from the provider `string` | `Array` authorizeUrl\* The URL to start the OAuth flow `string` tokenUrl\* The URL to exchange the authorization code for an access token `string` refreshTokenUrl The URL to refresh the access token if applicable `string` personalAccessToken A personal token if the provider supports it `string` onAuthorize A callback function that is called once the user has been properly logged in through OAuth when used with `withAccessToken` `string` bodyEncoding Specifies the format for sending the body of the request. `json` | `url-encoded` tokenResponseParser Some providers returns some non-standard token responses. Specifies how to parse the JSON response to get the access token `(response: unknown) => OAuth.TokenResponse` tokenRefreshResponseParser Some providers returns some non-standard refresh token responses. Specifies how to parse the JSON response to get the access token `(response: unknown) => OAuth.TokenResponse` ### [](https://developers.raycast.com/utilities/oauth/oauthservice#providerwithdefaultclientoptions) ProviderWithDefaultClientOptions Property Name Description Type scope\* The scope of the access requested from the provider `string` | `Array` clientId The app's client ID `string` authorizeUrl The URL to start the OAuth flow `string` tokenUrl The URL to exchange the authorization code for an access token `string` refreshTokenUrl The URL to refresh the access token if applicable `string` personalAccessToken A personal token if the provider supports it `string` onAuthorize A callback function that is called once the user has been properly logged in through OAuth when used with `withAccessToken` `string` bodyEncoding Specifies the format for sending the body of the request. `json` | `url-encoded` tokenResponseParser Some providers returns some non-standard token responses. Specifies how to parse the JSON response to get the access token `(response: unknown) => OAuth.TokenResponse` tokenRefreshResponseParser Some providers returns some non-standard refresh token responses. Specifies how to parse the JSON response to get the access token `(response: unknown) => OAuth.TokenResponse` [PreviousOAuth Utils](https://developers.raycast.com/utilities/oauth) [NextwithAccessToken](https://developers.raycast.com/utilities/oauth/withaccesstoken) Last updated 2 years ago * [Example](https://developers.raycast.com/utilities/oauth/oauthservice#example) * [Signature](https://developers.raycast.com/utilities/oauth/oauthservice#signature) * [Methods](https://developers.raycast.com/utilities/oauth/oauthservice#methods) * [Built-in Services](https://developers.raycast.com/utilities/oauth/oauthservice#built-in-services) * [Types](https://developers.raycast.com/utilities/oauth/oauthservice#types) * [OAuthServiceOptions](https://developers.raycast.com/utilities/oauth/oauthservice#oauthserviceoptions) * [ProviderOptions](https://developers.raycast.com/utilities/oauth/oauthservice#provideroptions) * [ProviderWithDefaultClientOptions](https://developers.raycast.com/utilities/oauth/oauthservice#providerwithdefaultclientoptions) Copy constructor(options: OAuthServiceOptions): OAuthService Copy OAuthService.authorize(): Promise; Copy const accessToken = await oauthService.authorize(); Copy OAuthService.asana: (options: ProviderWithDefaultClientOptions) => OAuthService Copy const asana = OAuthService.asana({ scope: "default" }); Copy OAuthService.github: (options: ProviderWithDefaultClientOptions) => OAuthService Copy const github = OAuthService.github({ scope: "repo user" }); Copy OAuthService.google: (options: ProviderOptions) => OAuthService Copy const google = OAuthService.google({ clientId: "custom-client-id", scope: "https://www.googleapis.com/auth/drive.readonly", }); Copy OAuthService.jira: (options: ProviderOptions) => OAuthService Copy const jira = OAuthService.jira({ clientId: "custom-client-id", scope: "read:jira-user read:jira-work offline_access", }); Copy OAuthService.linear: (options: ProviderOptions) => OAuthService Copy const linear = OAuthService.linear({ scope: "read write" }); Copy OAuthService.slack: (options: ProviderWithDefaultClientOptions) => OAuthService Copy const slack = OAuthService.slack({ scope: "emoji:read" }); Copy OAuthService.zoom: (options: ProviderOptions) => OAuthService Copy const zoom = OAuthService.zoom({ clientId: "custom-client-id", scope: "meeting:write", }); --- # v1.59.0 | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/misc/migration/v1.59.0.md) . This version changed the `transient` option of `Clipboard` to `concealed`. The `transient` option still work, but is now marked as deprecated and may be removed in a future version. You will get helpful hints in your code editor to migrate your extension, and as usual we provide automated [migrations](https://developers.raycast.com/misc/migration) to help with the transition. To migrate your extension manually, you need to ensure that all `Clipboard.copy` that specify `transient` are updated as follows: [](https://developers.raycast.com/misc/migration/v1.59.0#clipboard.copy-with-transient-option) `Clipboard.copy` with `transient` option -------------------------------------------------------------------------------------------------------------------------------------------- Copy Clipboard.copy(content, { transient: true }); // becomes Clipboard.copy(content, { concealed: true }); [](https://developers.raycast.com/misc/migration/v1.59.0#action.copytoclipboard-with-transient-prop) `Action.CopyToClipboard` with `transient` prop -------------------------------------------------------------------------------------------------------------------------------------------------------- Copy // becomes [Previousv1.51.0](https://developers.raycast.com/misc/migration/v1.51.0) [NextFAQ](https://developers.raycast.com/misc/faq) Last updated 2 years ago * [Clipboard.copy with transient option](https://developers.raycast.com/misc/migration/v1.59.0#clipboard.copy-with-transient-option) * [Action.CopyToClipboard with transient prop](https://developers.raycast.com/misc/migration/v1.59.0#action.copytoclipboard-with-transient-prop) --- # useLocalStorage | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/react-hooks/uselocalstorage.md) . A hook to manage a value in the local storage. [](https://developers.raycast.com/utilities/react-hooks/uselocalstorage#signature) Signature ------------------------------------------------------------------------------------------------- Copy function useLocalStorage(key: string, initialValue?: T): { value: T | undefined; setValue: (value: T) => Promise; removeValue: () => Promise; isLoading: boolean; } ### [](https://developers.raycast.com/utilities/react-hooks/uselocalstorage#arguments) Arguments * `key` - The key to use for the value in the local storage. * `initialValue` - The initial value to use if the key doesn't exist in the local storage. ### [](https://developers.raycast.com/utilities/react-hooks/uselocalstorage#return) Return Returns an object with the following properties: * `value` - The value from the local storage or the initial value if the key doesn't exist. * `setValue` - A function to update the value in the local storage. * `removeValue` - A function to remove the value from the local storage. * `isLoading` - A boolean indicating if the value is loading. [](https://developers.raycast.com/utilities/react-hooks/uselocalstorage#example) Example --------------------------------------------------------------------------------------------- [PrevioususeStreamJSON](https://developers.raycast.com/utilities/react-hooks/usestreamjson) [NextChangelog](https://developers.raycast.com/misc/changelog) Last updated 1 year ago * [Signature](https://developers.raycast.com/utilities/react-hooks/uselocalstorage#signature) * [Arguments](https://developers.raycast.com/utilities/react-hooks/uselocalstorage#arguments) * [Return](https://developers.raycast.com/utilities/react-hooks/uselocalstorage#return) * [Example](https://developers.raycast.com/utilities/react-hooks/uselocalstorage#example) Copy import { Action, ActionPanel, Color, Icon, List } from "@raycast/api"; import { useLocalStorage } from "@raycast/utils"; const exampleTodos = [\ { id: "1", title: "Buy milk", done: false },\ { id: "2", title: "Walk the dog", done: false },\ { id: "3", title: "Call mom", done: false },\ ]; export default function Command() { const { value: todos, setValue: setTodos, isLoading } = useLocalStorage("todos", exampleTodos); async function toggleTodo(id: string) { const newTodos = todos?.map((todo) => (todo.id === id ? { ...todo, done: !todo.done } : todo)) ?? []; await setTodos(newTodos); } return ( {todos?.map((todo) => ( toggleTodo(todo.id)} /> toggleTodo(todo.id)} /> } /> ))} ); } --- # useAI | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/react-hooks/useai.md) . Hook which asks the AI to answer a prompt and returns the [AsyncState](https://developers.raycast.com/utilities/react-hooks/useai#asyncstate) corresponding to the execution of the query. [](https://developers.raycast.com/utilities/react-hooks/useai#signature) Signature --------------------------------------------------------------------------------------- Copy function useAI( prompt: string, options?: { creativity?: AI.Creativity; model?: AI.Model; stream?: boolean; execute?: boolean; onError?: (error: Error) => void; onData?: (data: T) => void; onWillExecute?: (args: Parameters) => void; failureToastOptions?: Partial>; } ): AsyncState & { revalidate: () => void; }; ### [](https://developers.raycast.com/utilities/react-hooks/useai#arguments) Arguments * `prompt` is the prompt to ask the AI. With a few options: * `options.creativity` is a number between 0 and 2 to control the creativity of the answer. Concrete tasks, such as fixing grammar, require less creativity while open-ended questions, such as generating ideas, require more. * `options.model` is a string determining which AI model will be used to answer. * `options.stream` is a boolean controlling whether to stream the answer or only update the data when the entire answer has been received. By default, the `data` will be streamed. Including the [usePromise](https://developers.raycast.com/utilities/react-hooks/usepromise) 's options: * `options.execute` is a boolean to indicate whether to actually execute the function or not. This is useful for cases where one of the function's arguments depends on something that might not be available right away (for example, depends on some user inputs). Because React requires every hook to be defined on the render, this flag enables you to define the hook right away but wait until you have all the arguments ready to execute the function. * `options.onError` is a function called when an execution fails. By default, it will log the error and show a generic failure toast with an action to retry. * `options.onData` is a function called when an execution succeeds. * `options.onWillExecute` is a function called when an execution will start. * `options.failureToastOptions` are the options to customize the title, message, and primary action of the failure toast. ### [](https://developers.raycast.com/utilities/react-hooks/useai#return) Return Returns an object with the [AsyncState](https://developers.raycast.com/utilities/react-hooks/useai#asyncstate) corresponding to the execution of the function as well as a couple of methods to manipulate it. * `data`, `error`, `isLoading` - see [AsyncState](https://developers.raycast.com/utilities/react-hooks/useai#asyncstate) . * `revalidate` is a method to manually call the function with the same arguments again. [](https://developers.raycast.com/utilities/react-hooks/useai#example) Example ----------------------------------------------------------------------------------- [](https://developers.raycast.com/utilities/react-hooks/useai#types) Types ------------------------------------------------------------------------------- ### [](https://developers.raycast.com/utilities/react-hooks/useai#asyncstate) AsyncState An object corresponding to the execution state of the function. [PrevioususeSQL](https://developers.raycast.com/utilities/react-hooks/usesql) [NextuseFrecencySorting](https://developers.raycast.com/utilities/react-hooks/usefrecencysorting) Last updated 1 year ago * [Signature](https://developers.raycast.com/utilities/react-hooks/useai#signature) * [Arguments](https://developers.raycast.com/utilities/react-hooks/useai#arguments) * [Return](https://developers.raycast.com/utilities/react-hooks/useai#return) * [Example](https://developers.raycast.com/utilities/react-hooks/useai#example) * [Types](https://developers.raycast.com/utilities/react-hooks/useai#types) * [AsyncState](https://developers.raycast.com/utilities/react-hooks/useai#asyncstate) Copy import { Detail } from "@raycast/api"; import { useAI } from "@raycast/utils"; export default function Command() { const { data, isLoading } = useAI("Suggest 5 jazz songs"); return ; } Copy // Initial State { isLoading: true, // or `false` if `options.execute` is `false` data: undefined, error: undefined } // Success State { isLoading: false, data: string, error: undefined } // Error State { isLoading: false, data: undefined, error: Error } // Reloading State { isLoading: true, data: string | undefined, error: Error | undefined } --- # v1.37.0 | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/misc/migration/v1.37.0.md) . This version now depends on [React 18](https://reactjs.org/blog/2022/03/29/react-v18.html) . As part of this change, the `@raycast/api` package now has strong dependencies on `@types/react` and `@types/node` so those 2 packages shall be removed from your extension's devDependencies (this will be done automatically by `npx ray migrate`). There are no breaking changes introduced in React 18 so all your extensions will still work properly. However, there are some breaking changes in `@types/react` so you might have to do some minor tweaks if you use TypeScript. We had a [pass](https://github.com/raycast/extensions/compare/f/fix-ts) through all the extensions on the public repo. Notably, if you are using `raycast-toolkit` or `swr`, you will have to update them to their latest version. [](https://developers.raycast.com/misc/migration/v1.37.0#react-suspense) React Suspense -------------------------------------------------------------------------------------------- Suspense is an advanced feature of React. You do not need to use or understand it to build Raycast extensions (or any React application). We are not going to teach Suspense here but we will highlight how you can work with it in Raycast. You can now use Suspense in Raycast. We provide a top-level `Suspense` fallback so you don't have to. This fallback simply turns on the `isLoading` on the top level view. Copy import { List, Toast, showToast, ActionPanel, Action, Icon, popToRoot } from "@raycast/api"; import { useState, useCallback } from "react"; import * as twitter from "./oauth/twitter"; // a hook that suspends until a promise is resolved import { usePromise } from "./suspense-use-promise"; const promise = async (search: string) => { try { await twitter.authorize(); return await twitter.fetchItems(search); } catch (error) { console.error(error); showToast({ style: Toast.Style.Failure, title: String(error) }); return []; } }; export default function Command() { const [search, setSearch] = useState(""); const items = usePromise(promise, [search]); const logout = useCallback(() => { twitter.logout(); popToRoot(); }, []); const actionPanel = ( ); // no need to set the `isLoading` prop, Raycast will set it automatically // until the React application isn't suspended anymore return ( {items.map((item) => { return ( ); })} ); } [Previousv1.31.0](https://developers.raycast.com/misc/migration/v1.31.0) [Nextv1.42.0](https://developers.raycast.com/misc/migration/v1.42.0) Last updated 4 years ago --- # useFrecencySorting | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/react-hooks/usefrecencysorting.md) . Hook to sort an array by its frecency and provide methods to update the frecency of its items. Frecency is a measure that combines frequency and recency. The more often an item is visited, and the more recently an item is visited, the higher it will rank. [](https://developers.raycast.com/utilities/react-hooks/usefrecencysorting#signature) Signature ---------------------------------------------------------------------------------------------------- Copy function useFrecencySorting( data?: T[], options?: { namespace?: string; key?: (item: T) => string; sortUnvisited?: (a: T, b: T) => number; }, ): { data: T[]; visitItem: (item: T) => Promise; resetRanking: (item: T) => Promise; }; ### [](https://developers.raycast.com/utilities/react-hooks/usefrecencysorting#arguments) Arguments * `data` is the array to sort With a few options: * `options.namespace` is a string that can be used to namespace the frecency data (if you have multiple arrays that you want to sort in the same extension). * `options.key` is a function that should return a unique string for each item of the array to sort. By default, it will use `item.id`. If the items do not have an `id` field, this option is required. * `options.sortUnvisited` is a function to sort the items that have never been visited. By default, the order of the input will be preserved. ### [](https://developers.raycast.com/utilities/react-hooks/usefrecencysorting#return) Return Returns an object with the sorted array and some methods to update the frecency of the items. * `data` is the sorted array. The order will be preserved for items that have never been visited * `visitItem` is a method to use when an item is visited/used. It will increase its frecency. * `resetRanking` is a method that can be used to reset the frecency of an item. [](https://developers.raycast.com/utilities/react-hooks/usefrecencysorting#example) Example ------------------------------------------------------------------------------------------------ [PrevioususeAI](https://developers.raycast.com/utilities/react-hooks/useai) [NextuseStreamJSON](https://developers.raycast.com/utilities/react-hooks/usestreamjson) Last updated 2 years ago * [Signature](https://developers.raycast.com/utilities/react-hooks/usefrecencysorting#signature) * [Arguments](https://developers.raycast.com/utilities/react-hooks/usefrecencysorting#arguments) * [Return](https://developers.raycast.com/utilities/react-hooks/usefrecencysorting#return) * [Example](https://developers.raycast.com/utilities/react-hooks/usefrecencysorting#example) Copy import { List, ActionPanel, Action, Icon } from "@raycast/api"; import { useFetch, useFrecencySorting } from "@raycast/utils"; export default function Command() { const { isLoading, data } = useFetch("https://api.example"); const { data: sortedData, visitItem, resetRanking } = useFrecencySorting(data); return ( {sortedData.map((item) => ( visitItem(item)} /> visitItem(item)} /> resetRanking(item)} /> } /> ))} ); } --- # v1.28.0 | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/misc/migration/v1.28.0.md) . This version contains an overhaul of the API surface to improve its discoverability and its usage in a code editor. The aim was to reduce the number of top-level exports to make it easier to find the ones that matter. It also aligns it with the structure of the documentation. The previous API surface is still there, only deprecated. All of your existing extensions will continue to work. You will get helpful hints in your code editor to migrate your extension. [](https://developers.raycast.com/misc/migration/v1.28.0#clipboard) Clipboard ---------------------------------------------------------------------------------- The methods related to the [Clipboard](https://developers.raycast.com/api-reference/clipboard) can now be found under the `Clipboard` namespace. Copy import { Clipboard } from "@raycast/api"; // deprecated copyTextToClipboard await Clipboard.copy("text"); // deprecated clearClipboard await Clipboard.clear(); // deprecated pasteText await Clipboard.paste("text"); [](https://developers.raycast.com/misc/migration/v1.28.0#storage) Storage ------------------------------------------------------------------------------ The methods and interfaces related to the [Storage](https://developers.raycast.com/api-reference/storage) can now be found under the `LocalStorage` namespace. Copy import { LocalStorage } from "@raycast/api"; // deprecated allLocalStorageItems const items = await LocalStorage.allItems(); // deprecated getLocalStorageItem const item = await LocalStorage.getItem("key"); // deprecated setLocalStorageItem await LocalStorage.setItem("key", "value"); // deprecated removeLocalStorageItem await LocalStorage.removeItem("key"); // deprecated clearLocalStorage await LocalStorage.clear(); // we didn't expect you to use the Storage interfaces // but they are now also under LocalStorage // deprecated LocalStorageValue LocalStorage.Value; // deprecated LocalStorageValues LocalStorage.Values; [](https://developers.raycast.com/misc/migration/v1.28.0#feedback) Feedback -------------------------------------------------------------------------------- The main changes to the [Feedback](https://developers.raycast.com/api-reference/feedback) methods are related to the Toast: `showToast` now accepts a `Toast.Options` object as an argument and its style will default to `Toast.Style.Success`. The interfaces and enumerations of both the Toast and Alert can now be found under their respective namespaces. [](https://developers.raycast.com/misc/migration/v1.28.0#keyboard) Keyboard -------------------------------------------------------------------------------- The interfaces related to the [Keyboard](https://developers.raycast.com/api-reference/keyboard) can now be found under the `Keyboard` namespace. [](https://developers.raycast.com/misc/migration/v1.28.0#preferences) Preferences -------------------------------------------------------------------------------------- We are deprecating the `preferences` constant because we found it to be error-prone. Instead, you should always use `getPreferenceValues()` which allows for a type-safe access with fallback to the defaults. [](https://developers.raycast.com/misc/migration/v1.28.0#user-interface) User Interface -------------------------------------------------------------------------------------------- There are two important changes related to the React components: * `ActionPanel.Item` has been renamed to `Action`. All the specific actions are now nested under `Action`. This will make it easier to introduce and teach the concept of Action. * All the props interfaces are now accessible under their respective components ### [](https://developers.raycast.com/misc/migration/v1.28.0#color) Color The interfaces related to the [Color](https://developers.raycast.com/api-reference/user-interface/colors) can now be found under the `Color` namespace. ### [](https://developers.raycast.com/misc/migration/v1.28.0#image) Image The interfaces and enumerations related to the [Image](https://developers.raycast.com/api-reference/user-interface/icons-and-images) can now be found under the `Image` namespace. `Icon` is still a top-level export. [](https://developers.raycast.com/misc/migration/v1.28.0#misc) Misc ------------------------------------------------------------------------ * We are deprecating the `randomId` utility. It wasn't related to Raycast. Instead, you can use the [`nanoid`](https://github.com/ai/nanoid#readme) dependency. * We are deprecating the `useId` hook. It was used internally but there shouldn't be a use-case for it in your extensions. * We are deprecating the `useActionPanel` hook. Use the `ActionPanel` component instead. * We are deprecating the `render` method. You should `export default` your root component instead. [PreviousMigration](https://developers.raycast.com/misc/migration) [Nextv1.31.0](https://developers.raycast.com/misc/migration/v1.31.0) Last updated 4 years ago * [Clipboard](https://developers.raycast.com/misc/migration/v1.28.0#clipboard) * [Storage](https://developers.raycast.com/misc/migration/v1.28.0#storage) * [Feedback](https://developers.raycast.com/misc/migration/v1.28.0#feedback) * [Keyboard](https://developers.raycast.com/misc/migration/v1.28.0#keyboard) * [Preferences](https://developers.raycast.com/misc/migration/v1.28.0#preferences) * [User Interface](https://developers.raycast.com/misc/migration/v1.28.0#user-interface) * [Color](https://developers.raycast.com/misc/migration/v1.28.0#color) * [Image](https://developers.raycast.com/misc/migration/v1.28.0#image) * [Misc](https://developers.raycast.com/misc/migration/v1.28.0#misc) Copy import { showToast, Toast } from "@raycast/api"; // deprecated new Toast() const toast = await showToast({ title: "Toast title" }); // Success by default // deprecated showToast(ToastStyle.Failure, 'Toast title') await showToast({ title: "Toast title", style: Toast.Style.Failure }); Copy import { Alert, Toast } from "@raycast/api"; // deprecated ToastOptions Toast.Options; // deprecated ToastActionOptions Toast.ActionOptions; // deprecated ToastStyle Toast.Style; // deprecated AlertOptions Alert.Options; // deprecated AlertActionOptions Alert.ActionOptions; // deprecated AlertActionStyle Alert.ActionStyle; Copy import { Keyboard } from "@raycast/api"; // deprecated KeyboardShortcut Keyboard.Shortcut; // deprecated KeyModifier Keyboard.KeyModifier; // deprecated KeyEquivalent Keyboard.KeyEquivalent; Copy import { Action, List } from '@raycast/api' // deprecated ActionPanel.Item {}}> // deprecated CopyToClipboardAction // deprecated ListProps List.Props Copy import { Color } from "@raycast/api"; // deprecated DynamicColor Color.Dynamic; // deprecated ColorLike Color.ColorLike; Copy import { Image } from "@raycast/api"; // deprecated ImageLike Image.ImageLike; // deprecated ImageSource Image.Source; // deprecated ImageMask Image.Mask; --- # useForm | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/react-hooks/useform.md) . Hook that provides a high-level interface to work with Forms, and more particularly, with Form validations. It incorporates all the good practices to provide a great User Experience for your Forms. [](https://developers.raycast.com/utilities/react-hooks/useform#signature) Signature ----------------------------------------------------------------------------------------- Copy function useForm(props: { onSubmit: (values: T) => void | boolean | Promise; initialValues?: Partial; validation?: { [id in keyof T]?: ((value: T[id]) => string | undefined | null) | FormValidation; }; }): { handleSubmit: (values: T) => void | boolean | Promise; itemProps: { [id in keyof T]: Partial> & { id: string; }; }; setValidationError: (id: keyof T, error: ValidationError) => void; setValue: (id: K, value: T[K]) => void; values: T; focus: (id: keyof T) => void; reset: (initialValues?: Partial) => void; }; ### [](https://developers.raycast.com/utilities/react-hooks/useform#arguments) Arguments * `onSubmit` is a callback that will be called when the form is submitted and all validations pass. With a few options: * `initialValues` are the initial values to set when the Form is first rendered. * `validation` are the validation rules for the Form. A validation for a Form item is a function that takes the current value of the item as an argument and must return a string when the validation is failing. We also provide some shorthands for common cases, see [FormValidation](https://developers.raycast.com/utilities/react-hooks/useform#formvalidation) . ### [](https://developers.raycast.com/utilities/react-hooks/useform#return) Return Returns an object which contains the necessary methods and props to provide a good User Experience in your Form. * `handleSubmit` is a function to pass to the `onSubmit` prop of the `` element. It wraps the initial `onSubmit` argument with some goodies related to the validation. * `itemProps` are the props that must be passed to the `` elements to handle the validations. It also contains some additions for easy manipulation of the Form's data. * `values` is the current values of the Form. * `setValue` is a function that can be used to programmatically set the value of a specific field. * `setValidationError` is a function that can be used to programmatically set the validation of a specific field. * `focus` is a function that can be used to programmatically focus a specific field. * `reset` is a function that can be used to reset the values of the Form. Optionally, you can specify the values to set when the Form is reset. [](https://developers.raycast.com/utilities/react-hooks/useform#example) Example ------------------------------------------------------------------------------------- [](https://developers.raycast.com/utilities/react-hooks/useform#types) Types --------------------------------------------------------------------------------- ### [](https://developers.raycast.com/utilities/react-hooks/useform#formvalidation) FormValidation Shorthands for common validation cases #### [](https://developers.raycast.com/utilities/react-hooks/useform#enumeration-members) Enumeration members Name Description Required Show an error when the value of the item is empty [PrevioususeFetch](https://developers.raycast.com/utilities/react-hooks/usefetch) [NextuseExec](https://developers.raycast.com/utilities/react-hooks/useexec) Last updated 2 years ago * [Signature](https://developers.raycast.com/utilities/react-hooks/useform#signature) * [Arguments](https://developers.raycast.com/utilities/react-hooks/useform#arguments) * [Return](https://developers.raycast.com/utilities/react-hooks/useform#return) * [Example](https://developers.raycast.com/utilities/react-hooks/useform#example) * [Types](https://developers.raycast.com/utilities/react-hooks/useform#types) * [FormValidation](https://developers.raycast.com/utilities/react-hooks/useform#formvalidation) Copy import { Action, ActionPanel, Form, showToast, Toast } from "@raycast/api"; import { useForm, FormValidation } from "@raycast/utils"; interface SignUpFormValues { firstName: string; lastName: string; birthday: Date | null; password: string; number: string; hobbies: string[]; } export default function Command() { const { handleSubmit, itemProps } = useForm({ onSubmit(values) { showToast({ style: Toast.Style.Success, title: "Yay!", message: `${values.firstName} ${values.lastName} account created`, }); }, validation: { firstName: FormValidation.Required, lastName: FormValidation.Required, password: (value) => { if (value && value.length < 8) { return "Password must be at least 8 symbols"; } else if (!value) { return "The item is required"; } }, number: (value) => { if (value && value !== "2") { return "Please select '2'"; } }, }, }); return ( } > {[1, 2, 3, 4, 5, 6, 7].map((num) => { return ; })} ); } --- # OAuth | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/api-reference/oauth.md) . [](https://developers.raycast.com/api-reference/oauth#prerequisites) Prerequisites --------------------------------------------------------------------------------------- A Raycast extension can use OAuth for authorizing access to a provider's resources on the user's behalf. Since Raycast is a desktop app and the extensions are considered "public", we only support the [PKCE flow](https://datatracker.ietf.org/doc/html/rfc7636) (Proof Key for Code Exchange, pronounced β€œpixy”). This flow is the official recommendation for native clients that cannot keep a client secret. With PKCE, the client dynamically creates a secret and uses the secret again during code exchange, ensuring that only the client that performed the initial request can exchange the code for the access token (”proof of possession”). Providers such as Google, Twitter, GitLab, Spotify, Zoom, Asana or Dropbox are all PKCE-ready. However, if your provider doesn't support PKCE, you can use our [PKCE proxy](https://oauth.raycast.com/) . It allows extensions to securely use an OAuth flow without exposing any secret. [](https://developers.raycast.com/api-reference/oauth#oauth-flow) OAuth Flow --------------------------------------------------------------------------------- ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-73fbf2da0684ab57bbdba779e06b3bbcfb895a01%252Foauth-overlay-twitter.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=1d47de9b&sv=2) The OAuth flow from an extension looks like this: 1. The extension initiates the OAuth flow and starts authorization 2. Raycast shows the OAuth overlay ("Connect to provider…") 3. The user opens the provider's consent page in the web browser 4. After the user consent, the provider redirects back to Raycast 5. Raycast opens the extension where authorization is completed When the flow is complete, the extension has received an access token from the provider and can perform API calls. The API provides functions for securely storing and retrieving token sets, so that an extension can check whether the user is already logged in and whether an expired access token needs to be refreshed. Raycast also automatically shows a logout preference. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-fa10ad21218f2a0f28d9a4fef60575518e1c0f1a%252Foauth-overlay-twitter-success.webp%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=ca6be401&sv=2) [](https://developers.raycast.com/api-reference/oauth#oauth-app) OAuth App ------------------------------------------------------------------------------- You first need to register a new OAuth app with your provider. This is usually done in the provider's developer portal. After registering, you will receive a client ID. You also need to configure a redirect URI, see the next section. Note: Make sure to choose an app type that supports PKCE. Some providers still show you a client secret, which you don't need and should _not_ hardcode in the extension, or support PKCE only for certain types such as "desktop", "native" or "mobile" app types. [](https://developers.raycast.com/api-reference/oauth#authorizing) Authorizing ----------------------------------------------------------------------------------- An extension can initiate the OAuth flow and authorize by using the methods on [OAuth.PKCEClient](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient) . You can create a new client and configure it with a provider name, icon and description that will be shown in the OAuth overlay. You can also choose between different redirect methods; depending on which method you choose, you need to configure this value as redirect URI in your provider's registered OAuth app. (See the [OAuth.RedirectMethod](https://developers.raycast.com/api-reference/oauth#oauth.redirectmethod) docs for each method to get concrete examples for supported redirect URI.) If you can choose, use `OAuth.RedirectMethod.Web` and enter `https://raycast.com/redirect?packageName=Extension` (whether you have to add the `?packageName=Extension` depends on the provider). Next you create an authorization request with the authorization endpoint, client ID, and scope values. You receive all values from your provider's docs and when you register a new OAuth app. The returned [AuthorizationRequest](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequest) contains parameters such as the code challenge, verifier, state and redirect URI as standard OAuth authorization request. You can also customize the authorization URL through [OAuth.AuthorizationOptions](https://developers.raycast.com/api-reference/oauth#oauth.authorizationoptions) if you need to. To get the authorization code needed for the token exchange, you call [authorize](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-authorize) with the request from the previous step. This call shows the Raycast OAuth overlay and provides the user with an option to open the consent page in the web browser. The authorize promise is resolved after the redirect back to Raycast and into the extension: When in development mode, make sure not to trigger auto-reloading (e.g. by saving a file) while you're testing an active OAuth authorization and redirect. This would cause an OAuth state mismatch when you're redirected back into the extension since the client would be reinitialized on reload. Now that you have received the authorization code, you can exchange this code for an access token using your provider's token endpoint. This token exchange (and the following API calls) can be done with your preferred Node HTTP client library. Example using `node-fetch`: [](https://developers.raycast.com/api-reference/oauth#token-storage) Token Storage --------------------------------------------------------------------------------------- The PKCE client exposes methods for storing, retrieving and deleting token sets. A [TokenSet](https://developers.raycast.com/api-reference/oauth#oauth.tokenset) contains an access token and typically also a refresh token, expires value, and the current scope. Since this data is returned by the provider's token endpoint as standard OAuth JSON response, you can directly store the response ([OAuth.TokenResponse](https://developers.raycast.com/api-reference/oauth#oauth.tokenresponse) ) or alternatively use [OAuth.TokenSetOptions](https://developers.raycast.com/api-reference/oauth#oauth.tokensetoptions) : Once the token set is stored, Raycast will automatically show a logout preference for the extension. When the user logs out, the token set gets removed. The [TokenSet](https://developers.raycast.com/api-reference/oauth#oauth.tokenset) also enables you to check whether the user is logged in before starting the authorization flow: [](https://developers.raycast.com/api-reference/oauth#token-refresh) Token Refresh --------------------------------------------------------------------------------------- Since access tokens usually expire, an extension should provide a way to refresh the access token, otherwise users would be logged out or see errors. Some providers require you to add an offline scope so that you get a refresh token. (Twitter, for example, needs the scope `offline.access` or it only returns an access token.) A basic refresh flow could look like this: This code would run before starting the authorization flow. It checks the presence of a token set to see whether the user is logged in and then checks whether there is a refresh token and the token set is expired (through the convenience method `isExpired()` on the [TokenSet](https://developers.raycast.com/api-reference/oauth#oauth.tokenset) ). If it is expired, the token is refreshed and updated in the token set. Example using `node-fetch`: [](https://developers.raycast.com/api-reference/oauth#examples) Examples ----------------------------------------------------------------------------- We've provided [OAuth example integrations for Google, Twitter, and Dropbox](https://github.com/raycast/extensions/tree/main/examples/api-examples) that demonstrate the entire flow shown above. [](https://developers.raycast.com/api-reference/oauth#api-reference) API Reference --------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient) OAuth.PKCEClient Use [OAuth.PKCEClient.Options](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient.options) to configure what's shown on the OAuth overlay. #### [](https://developers.raycast.com/api-reference/oauth#signature) Signature #### [](https://developers.raycast.com/api-reference/oauth#example) Example #### [](https://developers.raycast.com/api-reference/oauth#methods) Methods Method [`authorizationRequest(options: AuthorizationRequestOptions): Promise`](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-authorizationrequest) [`authorize(options: AuthorizationRequest | AuthorizationOptions): Promise`](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-authorize) [`setTokens(options: TokenSetOptions | TokenResponse): Promise`](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-settokens) [`getTokens(): Promise`](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-gettokens) [`removeTokens(): Promise`](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-removetokens) ### [](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-authorizationrequest) OAuth.PKCEClient#authorizationRequest Creates an authorization request for the provided authorization endpoint, client ID, and scopes. You need to first create the authorization request before calling [authorize](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-authorize) . The generated code challenge for the PKCE request uses the S256 method. #### [](https://developers.raycast.com/api-reference/oauth#signature-1) Signature #### [](https://developers.raycast.com/api-reference/oauth#example-1) Example #### [](https://developers.raycast.com/api-reference/oauth#parameters) Parameters Name Type Description options\* [`AuthorizationRequestOptions`](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequestoptions) The options used to create the authorization request. #### [](https://developers.raycast.com/api-reference/oauth#return) Return A promise for an [AuthorizationRequest](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequest) that you can use as input for [authorize](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-authorize) . ### [](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-authorize) OAuth.PKCEClient#authorize Starts the authorization and shows the OAuth overlay in Raycast. As parameter you can either directly use the returned request from [authorizationRequest](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequest) , or customize the URL by extracting parameters from [AuthorizationRequest](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequest) and providing your own URL via [AuthorizationOptions](https://developers.raycast.com/api-reference/oauth#oauth.authorizationoptions) . Eventually the URL will be used to open the authorization page of the provider in the web browser. #### [](https://developers.raycast.com/api-reference/oauth#signature-2) Signature #### [](https://developers.raycast.com/api-reference/oauth#example-2) Example #### [](https://developers.raycast.com/api-reference/oauth#parameters-1) Parameters Name Type Description options\* [`AuthorizationRequest`](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequest) `|` [`AuthorizationOptions`](https://developers.raycast.com/api-reference/oauth#oauth.authorizationoptions) The options used to authorize. #### [](https://developers.raycast.com/api-reference/oauth#return-1) Return A promise for an [AuthorizationResponse](https://developers.raycast.com/api-reference/oauth#oauth.authorizationresponse) , which contains the authorization code needed for the token exchange. The promise is resolved when the user was redirected back from the provider's authorization page to the Raycast extension. ### [](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-settokens) OAuth.PKCEClient#setTokens Securely stores a [TokenSet](https://developers.raycast.com/api-reference/oauth#oauth.tokenset) for the provider. Use this after fetching the access token from the provider. If the provider returns a a standard OAuth JSON token response, you can directly pass the [TokenResponse](https://developers.raycast.com/api-reference/oauth#oauth.tokenresponse) . At a minimum, you need to set the `accessToken`, and typically you also set `refreshToken` and `isExpired`. Raycast automatically shows a logout preference for the extension when a token set was saved. If you want to make use of the convenience `isExpired()` method, the property `expiresIn` must be configured. #### [](https://developers.raycast.com/api-reference/oauth#signature-3) Signature #### [](https://developers.raycast.com/api-reference/oauth#example-3) Example #### [](https://developers.raycast.com/api-reference/oauth#parameters-2) Parameters Name Type Description options\* [`TokenSetOptions`](https://developers.raycast.com/api-reference/oauth#oauth.tokensetoptions) `|` [`TokenResponse`](https://developers.raycast.com/api-reference/oauth#oauth.tokenresponse) The options used to store the token set. #### [](https://developers.raycast.com/api-reference/oauth#return-2) Return A promise that resolves when the token set has been stored. ### [](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-gettokens) OAuth.PKCEClient#getTokens Retrieves the stored [TokenSet](https://developers.raycast.com/api-reference/oauth#oauth.tokenset) for the client. You can use this to initially check whether the authorization flow should be initiated or the user is already logged in and you might have to refresh the access token. #### [](https://developers.raycast.com/api-reference/oauth#signature-4) Signature #### [](https://developers.raycast.com/api-reference/oauth#example-4) Example #### [](https://developers.raycast.com/api-reference/oauth#return-3) Return A promise that resolves when the token set has been retrieved. ### [](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-removetokens) OAuth.PKCEClient#removeTokens Removes the stored [TokenSet](https://developers.raycast.com/api-reference/oauth#oauth.tokenset) for the client. Raycast automatically shows a logout preference that removes the token set. Use this method only if you need to provide an additional logout option in your extension or you want to remove the token set because of a migration. #### [](https://developers.raycast.com/api-reference/oauth#signature-5) Signature #### [](https://developers.raycast.com/api-reference/oauth#example-5) Example #### [](https://developers.raycast.com/api-reference/oauth#return-4) Return A promise that resolves when the token set has been removed. [](https://developers.raycast.com/api-reference/oauth#types) Types ----------------------------------------------------------------------- ### [](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient.options) OAuth.PKCEClient.Options The options for creating a new [PKCEClient](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient) . #### [](https://developers.raycast.com/api-reference/oauth#properties) Properties Property Description Type providerName\* The name of the provider, displayed in the OAuth overlay. `string` redirectMethod\* The redirect method for the OAuth flow. Make sure to set this to the correct method for the provider, see OAuth.RedirectMethod for more information. [`OAuth.RedirectMethod`](https://developers.raycast.com/api-reference/oauth#oauth.redirectmethod) description An optional description, shown in the OAuth overlay. You can use this to customize the message for the end user, for example for handling scope changes or other migrations. Raycast shows a default message if this is not configured. `string` providerIcon An icon displayed in the OAuth overlay. Make sure to provide at least a size of 64x64 pixels. [`Image.ImageLike`](https://developers.raycast.com/api-reference/user-interface/icons-and-images#image.imagelike) providerId An optional ID for associating the client with a provider. Only set this if you use multiple different clients in your extension. `string` ### [](https://developers.raycast.com/api-reference/oauth#oauth.redirectmethod) OAuth.RedirectMethod Defines the supported redirect methods for the OAuth flow. You can choose between web and app-scheme redirect methods, depending on what the provider requires when setting up the OAuth app. For examples on what redirect URI you need to configure, see the docs for each method. #### [](https://developers.raycast.com/api-reference/oauth#enumeration-members) Enumeration members Name Value Web Use this type for a redirect back to the Raycast website, which will then open the extension. In the OAuth app, configure `https://raycast.com/redirect?packageName=Extension` (This is a static redirect URL for all extensions.) If the provider does not accept query parameters in redirect URLs, you can alternatively use `https://raycast.com/redirect/extension` and then customize the [AuthorizationRequest](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequest) via its `extraParameters` property. For example add: `extraParameters: { "redirect_uri": "https://raycast.com/redirect/extension" }` App Use this type for an app-scheme based redirect that directly opens Raycast. In the OAuth app, configure `raycast://oauth?package_name=Extension` AppURI Use this type for a URI-style app scheme that directly opens Raycast. In the OAuth app, configure `com.raycast:/oauth?package_name=Extension` (Note the single slash – Google, for example, would require this flavor for an OAuth app where the Bundle ID is `com.raycast`) ### [](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequestoptions) OAuth.AuthorizationRequestOptions The options for an authorization request via [authorizationRequest](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequest) . Property Description Type clientId\* The client ID of the configured OAuth app. `string` endpoint\* The URL to the authorization endpoint for the OAuth provider. `string` scope\* A space-delimited list of scopes for identifying the resources to access on the user's behalf. The scopes are typically shown to the user on the provider's consent screen in the browser. Note that some providers require the same scopes be configured in the registered OAuth app. `string` extraParameters Optional additional parameters for the authorization request. Note that some providers require additional parameters, for example to obtain long-lived refresh tokens. `{ [string]: string }` ### [](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequesturlparams) OAuth.AuthorizationRequestURLParams Values of [AuthorizationRequest](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequest) . The PKCE client automatically generates the values for you and returns them for [authorizationRequest](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequest) Property Description Type codeChallenge\* The PKCE `code_challenge` value. `string` codeVerifier\* The PKCE `code_verifier` value. `string` redirectURI\* The OAuth `redirect_uri` value. `string` state\* The OAuth `state` value. `string` ### [](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequest) OAuth.AuthorizationRequest The request returned by [authorizationRequest](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequest) . Can be used as direct input to [authorize](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-authorize) , or to extract parameters for constructing a custom URL in [AuthorizationOptions](https://developers.raycast.com/api-reference/oauth#oauth.authorizationoptions) . Property Description Type codeChallenge\* The PKCE `code_challenge` value. `string` codeVerifier\* The PKCE `code_verifier` value. `string` redirectURI\* The OAuth `redirect_uri` value. `string` state\* The OAuth `state` value. `string` toURL\* `() => string` #### [](https://developers.raycast.com/api-reference/oauth#methods-1) Methods Name Type Description toURL() `() => string` Constructs the full authorization URL. ### [](https://developers.raycast.com/api-reference/oauth#oauth.authorizationoptions) OAuth.AuthorizationOptions Options for customizing [authorize](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-authorize) . You can use values from [AuthorizationRequest](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequest) to build your own URL. Property Description Type url\* The full authorization URL. `string` ### [](https://developers.raycast.com/api-reference/oauth#oauth.authorizationresponse) OAuth.AuthorizationResponse The response returned by [authorize](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-authorize) , containing the authorization code after the provider redirect. You can then exchange the authorization code for an access token using the provider's token endpoint. Property Description Type authorizationCode\* The authorization code from the OAuth provider. `string` ### [](https://developers.raycast.com/api-reference/oauth#oauth.tokenset) OAuth.TokenSet Describes the TokenSet created from an OAuth provider's token response. The `accessToken` is the only required parameter but typically OAuth providers also return a refresh token, an expires value, and the scope. Securely store a token set via [setTokens](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-settokens) and retrieve it via [getTokens](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-gettokens) . Property Description Type accessToken\* The access token returned by an OAuth token request. `string` updatedAt\* The date when the token set was stored via OAuth.PKCEClient.setTokens. [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) isExpired\* `() => boolean` expiresIn An optional expires value (in seconds) returned by an OAuth token request. `number` idToken An optional id token returned by an identity request (e.g. /me, Open ID Connect). `string` refreshToken An optional refresh token returned by an OAuth token request. `string` scope The optional space-delimited list of scopes returned by an OAuth token request. You can use this to compare the currently stored access scopes against new access scopes the extension might require in a future version, and then ask the user to re-authorize with new scopes. `string` #### [](https://developers.raycast.com/api-reference/oauth#methods-2) Methods Name Type Description isExpired() `() => boolean` A convenience method for checking whether the access token has expired. The method factors in some seconds of "buffer", so it returns true a couple of seconds before the actual expiration time. This requires the `expiresIn` parameter to be set. ### [](https://developers.raycast.com/api-reference/oauth#oauth.tokensetoptions) OAuth.TokenSetOptions Options for a [TokenSet](https://developers.raycast.com/api-reference/oauth#oauth.tokenset) to store via [setTokens](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-settokens) . Property Description Type accessToken\* The access token returned by an OAuth token request. `string` expiresIn An optional expires value (in seconds) returned by an OAuth token request. `number` idToken An optional id token returned by an identity request (e.g. /me, Open ID Connect). `string` refreshToken An optional refresh token returned by an OAuth token request. `string` scope The optional scope value returned by an OAuth token request. `string` ### [](https://developers.raycast.com/api-reference/oauth#oauth.tokenresponse) OAuth.TokenResponse Defines the standard JSON response for an OAuth token request. The response can be directly used to store a [TokenSet](https://developers.raycast.com/api-reference/oauth#oauth.tokenset) via [setTokens](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-settokens) . Property Description Type access\_token\* The `access_token` value returned by an OAuth token request. `string` expires\_in An optional `expires_in` value (in seconds) returned by an OAuth token request. `number` id\_token An optional `id_token` value returned by an identity request (e.g. /me, Open ID Connect). `string` refresh\_token An optional `refresh_token` value returned by an OAuth token request. `string` scope The optional `scope` value returned by an OAuth token request. `string` [PreviousMenu Bar Commands](https://developers.raycast.com/api-reference/menu-bar-commands) [NextPreferences](https://developers.raycast.com/api-reference/preferences) Last updated 4 months ago * [Prerequisites](https://developers.raycast.com/api-reference/oauth#prerequisites) * [OAuth Flow](https://developers.raycast.com/api-reference/oauth#oauth-flow) * [OAuth App](https://developers.raycast.com/api-reference/oauth#oauth-app) * [Authorizing](https://developers.raycast.com/api-reference/oauth#authorizing) * [Token Storage](https://developers.raycast.com/api-reference/oauth#token-storage) * [Token Refresh](https://developers.raycast.com/api-reference/oauth#token-refresh) * [Examples](https://developers.raycast.com/api-reference/oauth#examples) * [API Reference](https://developers.raycast.com/api-reference/oauth#api-reference) * [OAuth.PKCEClient](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient) * [OAuth.PKCEClient#authorizationRequest](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-authorizationrequest) * [OAuth.PKCEClient#authorize](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-authorize) * [OAuth.PKCEClient#setTokens](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-settokens) * [OAuth.PKCEClient#getTokens](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-gettokens) * [OAuth.PKCEClient#removeTokens](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient-removetokens) * [Types](https://developers.raycast.com/api-reference/oauth#types) * [OAuth.PKCEClient.Options](https://developers.raycast.com/api-reference/oauth#oauth.pkceclient.options) * [OAuth.RedirectMethod](https://developers.raycast.com/api-reference/oauth#oauth.redirectmethod) * [OAuth.AuthorizationRequestOptions](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequestoptions) * [OAuth.AuthorizationRequestURLParams](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequesturlparams) * [OAuth.AuthorizationRequest](https://developers.raycast.com/api-reference/oauth#oauth.authorizationrequest) * [OAuth.AuthorizationOptions](https://developers.raycast.com/api-reference/oauth#oauth.authorizationoptions) * [OAuth.AuthorizationResponse](https://developers.raycast.com/api-reference/oauth#oauth.authorizationresponse) * [OAuth.TokenSet](https://developers.raycast.com/api-reference/oauth#oauth.tokenset) * [OAuth.TokenSetOptions](https://developers.raycast.com/api-reference/oauth#oauth.tokensetoptions) * [OAuth.TokenResponse](https://developers.raycast.com/api-reference/oauth#oauth.tokenresponse) Copy import { OAuth } from "@raycast/api"; const client = new OAuth.PKCEClient({ redirectMethod: OAuth.RedirectMethod.Web, providerName: "Twitter", providerIcon: "twitter-logo.png", description: "Connect your Twitter account…", }); Copy const authRequest = await client.authorizationRequest({ endpoint: "https://twitter.com/i/oauth2/authorize", clientId: "YourClientId", scope: "tweet.read users.read follows.read", }); Copy const { authorizationCode } = await client.authorize(authRequest); Copy async function fetchTokens(authRequest: OAuth.AuthorizationRequest, authCode: string): Promise { const params = new URLSearchParams(); params.append("client_id", "YourClientId"); params.append("code", authCode); params.append("code_verifier", authRequest.codeVerifier); params.append("grant_type", "authorization_code"); params.append("redirect_uri", authRequest.redirectURI); const response = await fetch("https://api.twitter.com/2/oauth2/token", { method: "POST", body: params, }); if (!response.ok) { console.error("fetch tokens error:", await response.text()); throw new Error(response.statusText); } return (await response.json()) as OAuth.TokenResponse; } Copy await client.setTokens(tokenResponse); Copy const tokenSet = await client.getTokens(); Copy const tokenSet = await client.getTokens(); if (tokenSet?.accessToken) { if (tokenSet.refreshToken && tokenSet.isExpired()) { await client.setTokens(await refreshTokens(tokenSet.refreshToken)); } return; } // authorize... Copy async function refreshTokens(refreshToken: string): Promise { const params = new URLSearchParams(); params.append("client_id", "YourClientId"); params.append("refresh_token", refreshToken); params.append("grant_type", "refresh_token"); const response = await fetch("https://api.twitter.com/2/oauth2/token", { method: "POST", body: params, }); if (!response.ok) { console.error("refresh tokens error:", await response.text()); throw new Error(response.statusText); } const tokenResponse = (await response.json()) as OAuth.TokenResponse; tokenResponse.refresh_token = tokenResponse.refresh_token ?? refreshToken; return tokenResponse; } Copy constructor(options: OAuth.PKCEClient.Options): OAuth.PKCEClient Copy import { OAuth } from "@raycast/api"; const client = new OAuth.PKCEClient({ redirectMethod: OAuth.RedirectMethod.Web, providerName: "Twitter", providerIcon: "twitter-logo.png", description: "Connect your Twitter account…", }); Copy authorizationRequest(options: AuthorizationRequestOptions): Promise; Copy const authRequest = await client.authorizationRequest({ endpoint: "https://twitter.com/i/oauth2/authorize", clientId: "YourClientId", scope: "tweet.read users.read follows.read", }); Copy authorize(options: AuthorizationRequest | AuthorizationOptions): Promise; Copy const { authorizationCode } = await client.authorize(authRequest); Copy setTokens(options: TokenSetOptions | TokenResponse): Promise; Copy await client.setTokens(tokenResponse); Copy getTokens(): Promise; Copy const tokenSet = await client.getTokens(); Copy removeTokens(): Promise; Copy await client.removeTokens(); --- # useSQL | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/react-hooks/usesql.md) . Hook which executes a query on a local SQL database and returns the [AsyncState](https://developers.raycast.com/utilities/react-hooks/usesql#asyncstate) corresponding to the execution of the query. [](https://developers.raycast.com/utilities/react-hooks/usesql#signature) Signature ---------------------------------------------------------------------------------------- Copy function useSQL( databasePath: string, query: string, options?: { permissionPriming?: string; execute?: boolean; onError?: (error: Error) => void; onData?: (data: T) => void; onWillExecute?: (args: string[]) => void; failureToastOptions?: Partial>; } ): AsyncState & { revalidate: () => void; mutate: MutatePromise; permissionView: React.ReactNode | undefined; }; ### [](https://developers.raycast.com/utilities/react-hooks/usesql#arguments) Arguments * `databasePath` is the path to the local SQL database. * `query` is the SQL query to run on the database. With a few options: * `options.permissionPriming` is a string explaining why the extension needs full disk access. For example, the Apple Notes extension uses `"This is required to search your Apple Notes."`. While it is optional, we recommend setting it to help users understand. Including the [usePromise](https://developers.raycast.com/utilities/react-hooks/usepromise) 's options: * `options.execute` is a boolean to indicate whether to actually execute the function or not. This is useful for cases where one of the function's arguments depends on something that might not be available right away (for example, depends on some user inputs). Because React requires every hook to be defined on the render, this flag enables you to define the hook right away but wait until you have all the arguments ready to execute the function. * `options.onError` is a function called when an execution fails. By default, it will log the error and show a generic failure toast with an action to retry. * `options.onData` is a function called when an execution succeeds. * `options.onWillExecute` is a function called when an execution will start. * `options.failureToastOptions` are the options to customize the title, message, and primary action of the failure toast. ### [](https://developers.raycast.com/utilities/react-hooks/usesql#return) Return Returns an object with the [AsyncState](https://developers.raycast.com/utilities/react-hooks/usesql#asyncstate) corresponding to the execution of the function as well as a couple of methods to manipulate it. * `data`, `error`, `isLoading` - see [AsyncState](https://developers.raycast.com/utilities/react-hooks/usesql#asyncstate) . * `permissionView` is a React Node that should be returned when present. It will prompt users to grant full disk access (which is required for the hook to work). * `revalidate` is a method to manually call the function with the same arguments again. * `mutate` is a method to wrap an asynchronous update and gives some control over how the `useSQL`'s data should be updated while the update is going through. By default, the data will be revalidated (eg. the function will be called again) after the update is done. See [Mutation and Optimistic Updates](https://developers.raycast.com/utilities/react-hooks/usesql#mutation-and-optimistic-updates) for more information. [](https://developers.raycast.com/utilities/react-hooks/usesql#example) Example ------------------------------------------------------------------------------------ [](https://developers.raycast.com/utilities/react-hooks/usesql#mutation-and-optimistic-updates) Mutation and Optimistic Updates ------------------------------------------------------------------------------------------------------------------------------------ In an optimistic update, the UI behaves as though a change was successfully completed before receiving confirmation from the server that it was - it is being optimistic that it will eventually get the confirmation rather than an error. This allows for a more responsive user experience. You can specify an `optimisticUpdate` function to mutate the data in order to reflect the change introduced by the asynchronous update. When doing so, you can specify a `rollbackOnError` function to mutate back the data if the asynchronous update fails. If not specified, the data will be automatically rolled back to its previous value (before the optimistic update). [](https://developers.raycast.com/utilities/react-hooks/usesql#types) Types -------------------------------------------------------------------------------- ### [](https://developers.raycast.com/utilities/react-hooks/usesql#asyncstate) AsyncState An object corresponding to the execution state of the function. ### [](https://developers.raycast.com/utilities/react-hooks/usesql#mutatepromise) MutatePromise A method to wrap an asynchronous update and gives some control about how the `useSQL`'s data should be updated while the update is going through. [PrevioususeExec](https://developers.raycast.com/utilities/react-hooks/useexec) [NextuseAI](https://developers.raycast.com/utilities/react-hooks/useai) Last updated 1 year ago * [Signature](https://developers.raycast.com/utilities/react-hooks/usesql#signature) * [Arguments](https://developers.raycast.com/utilities/react-hooks/usesql#arguments) * [Return](https://developers.raycast.com/utilities/react-hooks/usesql#return) * [Example](https://developers.raycast.com/utilities/react-hooks/usesql#example) * [Mutation and Optimistic Updates](https://developers.raycast.com/utilities/react-hooks/usesql#mutation-and-optimistic-updates) * [Types](https://developers.raycast.com/utilities/react-hooks/usesql#types) * [AsyncState](https://developers.raycast.com/utilities/react-hooks/usesql#asyncstate) * [MutatePromise](https://developers.raycast.com/utilities/react-hooks/usesql#mutatepromise) Copy import { useSQL } from "@raycast/utils"; import { resolve } from "path"; import { homedir } from "os"; const NOTES_DB = resolve(homedir(), "Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"); const notesQuery = `SELECT id, title FROM ...`; type NoteItem = { id: string; title: string; }; export default function Command() { const { isLoading, data, permissionView } = useSQL(NOTES_DB, notesQuery); if (permissionView) { return permissionView; } return ( {(data || []).map((item) => ( ))} ); } Copy import { Detail, ActionPanel, Action, showToast, Toast } from "@raycast/api"; import { useSQL } from "@raycast/utils"; const NOTES_DB = resolve(homedir(), "Library/Group Containers/group.com.apple.notes/NoteStore.sqlite"); const notesQuery = `SELECT id, title FROM ...`; type NoteItem = { id: string; title: string; }; export default function Command() { const { isLoading, data, mutate, permissionView } = useFetch("https://api.example"); if (permissionView) { return permissionView; } const createNewNote = async () => { const toast = await showToast({ style: Toast.Style.Animated, title: "Creating new Note" }); try { await mutate( // we are calling an API to do something somehowCreateANewNote(), { // but we are going to do it on our local data right away, // without waiting for the call to return optimisticUpdate(data) { return data?.concat([{ id: "" + Math.random(), title: "New Title" }]); }, }, ); // yay, the API call worked! toast.style = Toast.Style.Success; toast.title = "Note created"; } catch (err) { // oh, the API call didn't work :( // the data will automatically be rolled back to its previous value toast.style = Toast.Style.Failure; toast.title = "Could not create Note"; toast.message = err.message; } }; return ( {(data || []).map((item) => ( createNewNote()} /> } /> ))} ); } Copy // Initial State { isLoading: true, // or `false` if `options.execute` is `false` data: undefined, error: undefined } // Success State { isLoading: false, data: T, error: undefined } // Error State { isLoading: false, data: undefined, error: Error } // Reloading State { isLoading: true, data: T | undefined, error: Error | undefined } Copy export type MutatePromise = ( asyncUpdate?: Promise, options?: { optimisticUpdate?: (data: T) => T; rollbackOnError?: boolean | ((data: T) => T); shouldRevalidateAfter?: boolean; }, ) => Promise; --- # usePromise | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/react-hooks/usepromise.md) . Hook which wraps an asynchronous function or a function that returns a Promise and returns the [AsyncState](https://developers.raycast.com/utilities/react-hooks/usepromise#asyncstate) corresponding to the execution of the function. The function is assumed to be constant (eg. changing it won't trigger a revalidation). [](https://developers.raycast.com/utilities/react-hooks/usepromise#signature) Signature -------------------------------------------------------------------------------------------- Copy type Result = `type of the returned value of the returned Promise`; function usePromise( fn: T, args?: Parameters, options?: { abortable?: RefObject; execute?: boolean; onError?: (error: Error) => void; onData?: (data: Result) => void; onWillExecute?: (args: Parameters) => void; failureToastOptions?: Partial>; }, ): AsyncState> & { revalidate: () => void; mutate: MutatePromise | undefined>; }; ### [](https://developers.raycast.com/utilities/react-hooks/usepromise#arguments) Arguments * `fn` is an asynchronous function or a function that returns a Promise. * `args` is the array of arguments to pass to the function. Every time they change, the function will be executed again. You can omit the array if the function doesn't require any argument. With a few options: * `options.abortable` is a reference to an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) to cancel a previous call when triggering a new one. * `options.execute` is a boolean to indicate whether to actually execute the function or not. This is useful for cases where one of the function's arguments depends on something that might not be available right away (for example, depends on some user inputs). Because React requires every hook to be defined on the render, this flag enables you to define the hook right away but wait until you have all the arguments ready to execute the function. * `options.onError` is a function called when an execution fails. By default, it will log the error and show a generic failure toast with an action to retry. * `options.onData` is a function called when an execution succeeds. * `options.onWillExecute` is a function called when an execution will start. * `options.failureToastOptions` are the options to customize the title, message, and primary action of the failure toast. ### [](https://developers.raycast.com/utilities/react-hooks/usepromise#returns) Returns Returns an object with the [AsyncState](https://developers.raycast.com/utilities/react-hooks/usepromise#asyncstate) corresponding to the execution of the function as well as a couple of methods to manipulate it. * `data`, `error`, `isLoading` - see [AsyncState](https://developers.raycast.com/utilities/react-hooks/usepromise#asyncstate) . * `revalidate` is a method to manually call the function with the same arguments again. * `mutate` is a method to wrap an asynchronous update and gives some control about how the `usePromise`'s data should be updated while the update is going through. By default, the data will be revalidated (eg. the function will be called again) after the update is done. See [Mutation and Optimistic Updates](https://developers.raycast.com/utilities/react-hooks/usepromise#mutation-and-optimistic-updates) for more information. [](https://developers.raycast.com/utilities/react-hooks/usepromise#example) Example ---------------------------------------------------------------------------------------- [](https://developers.raycast.com/utilities/react-hooks/usepromise#mutation-and-optimistic-updates) Mutation and Optimistic Updates ---------------------------------------------------------------------------------------------------------------------------------------- In an optimistic update, the UI behaves as though a change was successfully completed before receiving confirmation from the server that it was - it is being optimistic that it will eventually get the confirmation rather than an error. This allows for a more responsive user experience. You can specify an `optimisticUpdate` function to mutate the data in order to reflect the change introduced by the asynchronous update. When doing so, you can specify a `rollbackOnError` function to mutate back the data if the asynchronous update fails. If not specified, the data will be automatically rolled back to its previous value (before the optimistic update). [](https://developers.raycast.com/utilities/react-hooks/usepromise#pagination) Pagination ---------------------------------------------------------------------------------------------- The hook has built-in support for pagination. In order to enable pagination, `fn`'s type needs to change from > an asynchronous function or a function that returns a Promise to > a function that returns an asynchronous function or a function that returns a Promise In practice, this means going from to or, if your data source uses cursor-based pagination, you can return a `cursor` alongside `data` and `hasMore`, and the cursor will be passed as an argument the next time the function gets called: You'll notice that, in the second case, the hook returns an additional item: `pagination`. This can be passed to Raycast's `List` or `Grid` components in order to enable pagination. Another thing to notice is that the async function receives a [PaginationOptions](https://developers.raycast.com/utilities/react-hooks/usepromise#paginationoptions) argument, and returns a specific data format: Every time the promise resolves, the hook needs to figure out if it should paginate further, or if it should stop, and it uses `hasMore` for this. In addition to this, the hook also needs `data`, and needs it to be an array, because internally it appends it to a list, thus making sure the `data` that the hook _returns_ always contains the data for all of the pages that have been loaded so far. Additionally, you can also pass a `cursor` property, which will be included along with `page` and `lastItem` in the next pagination call. ### [](https://developers.raycast.com/utilities/react-hooks/usepromise#full-example) Full Example [](https://developers.raycast.com/utilities/react-hooks/usepromise#types) Types ------------------------------------------------------------------------------------ ### [](https://developers.raycast.com/utilities/react-hooks/usepromise#asyncstate) AsyncState An object corresponding to the execution state of the function. ### [](https://developers.raycast.com/utilities/react-hooks/usepromise#mutatepromise) MutatePromise A method to wrap an asynchronous update and gives some control about how the `usePromise`'s data should be updated while the update is going through. ### [](https://developers.raycast.com/utilities/react-hooks/usepromise#paginationoptions) PaginationOptions An object passed to a `PaginatedPromise`, it has two properties: * `page`: 0-indexed, this it's incremented every time the promise resolves, and is reset whenever `revalidate()` is called. * `lastItem`: this is a copy of the last item in the `data` array from the last time the promise was executed. Provided for APIs that implement cursor-based pagination. * `cursor`: this is the `cursor` property returned after the previous execution of `PaginatedPromise`. Useful when working with APIs that provide the next cursor explicitly. [PrevioususeCachedState](https://developers.raycast.com/utilities/react-hooks/usecachedstate) [NextuseCachedPromise](https://developers.raycast.com/utilities/react-hooks/usecachedpromise) Last updated 1 year ago * [Signature](https://developers.raycast.com/utilities/react-hooks/usepromise#signature) * [Arguments](https://developers.raycast.com/utilities/react-hooks/usepromise#arguments) * [Returns](https://developers.raycast.com/utilities/react-hooks/usepromise#returns) * [Example](https://developers.raycast.com/utilities/react-hooks/usepromise#example) * [Mutation and Optimistic Updates](https://developers.raycast.com/utilities/react-hooks/usepromise#mutation-and-optimistic-updates) * [Pagination](https://developers.raycast.com/utilities/react-hooks/usepromise#pagination) * [Full Example](https://developers.raycast.com/utilities/react-hooks/usepromise#full-example) * [Types](https://developers.raycast.com/utilities/react-hooks/usepromise#types) * [AsyncState](https://developers.raycast.com/utilities/react-hooks/usepromise#asyncstate) * [MutatePromise](https://developers.raycast.com/utilities/react-hooks/usepromise#mutatepromise) * [PaginationOptions](https://developers.raycast.com/utilities/react-hooks/usepromise#paginationoptions) Copy import { Detail, ActionPanel, Action } from "@raycast/api"; import { usePromise } from "@raycast/utils"; export default function Command() { const abortable = useRef(); const { isLoading, data, revalidate } = usePromise( async (url: string) => { const response = await fetch(url, { signal: abortable.current?.signal }); const result = await response.text(); return result; }, ["https://api.example"], { abortable, }, ); return ( revalidate()} /> } /> ); } Copy import { Detail, ActionPanel, Action, showToast, Toast } from "@raycast/api"; import { usePromise } from "@raycast/utils"; export default function Command() { const { isLoading, data, mutate } = usePromise( async (url: string) => { const response = await fetch(url); const result = await response.text(); return result; }, ["https://api.example"], ); const appendFoo = async () => { const toast = await showToast({ style: Toast.Style.Animated, title: "Appending Foo" }); try { await mutate( // we are calling an API to do something fetch("https://api.example/append-foo"), { // but we are going to do it on our local data right away, // without waiting for the call to return optimisticUpdate(data) { return data + "foo"; }, }, ); // yay, the API call worked! toast.style = Toast.Style.Success; toast.title = "Foo appended"; } catch (err) { // oh, the API call didn't work :( // the data will automatically be rolled back to its previous value toast.style = Toast.Style.Failure; toast.title = "Could not append Foo"; toast.message = err.message; } }; return ( appendFoo()} /> } /> ); } Copy const { isLoading, data } = usePromise( async (searchText: string) => { const data = await getUser(); // or any asynchronous logic you need to perform return data; }, [searchText], ); Copy const { isLoading, data, pagination } = usePromise( (searchText: string) => async ({ page, lastItem, cursor }) => { const { data } = await getUsers(page); // or any other asynchronous logic you need to perform const hasMore = page < 50; return { data, hasMore }; }, [searchText], ); Copy const { isLoading, data, pagination } = usePromise( (searchText: string) => async ({ page, lastItem, cursor }) => { const { data, nextCursor } = await getUsers(cursor); // or any other asynchronous logic you need to perform const hasMore = nextCursor !== undefined; return { data, hasMore, cursor: nextCursor }; }, [searchText], ); Copy { data: any[]; hasMore: boolean; cursor?: any; } Copy import { setTimeout } from "node:timers/promises"; import { useState } from "react"; import { List } from "@raycast/api"; import { usePromise } from "@raycast/utils"; export default function Command() { const [searchText, setSearchText] = useState(""); const { isLoading, data, pagination } = usePromise( (searchText: string) => async (options: { page: number }) => { await setTimeout(200); const newData = Array.from({ length: 25 }, (_v, index) => ({ index, page: options.page, text: searchText, })); return { data: newData, hasMore: options.page < 10 }; }, [searchText], ); return ( {data?.map((item) => ( ))} ); } Copy // Initial State { isLoading: true, // or `false` if `options.execute` is `false` data: undefined, error: undefined } // Success State { isLoading: false, data: T, error: undefined } // Error State { isLoading: false, data: undefined, error: Error } // Reloading State { isLoading: true, data: T | undefined, error: Error | undefined } Copy export type MutatePromise = ( asyncUpdate?: Promise, options?: { optimisticUpdate?: (data: T) => T; rollbackOnError?: boolean | ((data: T) => T); shouldRevalidateAfter?: boolean; }, ) => Promise; Copy export type PaginationOptions = { page: number; lastItem?: T; cursor?: any; }; --- # Getting Started | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/getting-started.md) . In addition to the [Raycast API](https://developers.raycast.com/api-reference/cache) which is bundled as part of the app, we also provide a sibling package that contains a set of utilities to streamline common patterns and operations used in extensions. ![](https://developers.raycast.com/~gitbook/image?url=https%3A%2F%2F2922539984-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252F-Me_8A39tFhZg3UaVoSN%252Fuploads%252Fgit-blob-2bee6f8564b36459e1157c54b2a542bf035a28d7%252Futils-illustration.jpg%3Falt%3Dmedia&width=768&dpr=3&quality=100&sign=d50dfcec&sv=2) [](https://developers.raycast.com/utilities/getting-started#installation) Installation ------------------------------------------------------------------------------------------- This package can be installed independently using `npm`. `@raycast/utils` has a [peer dependency](https://docs.npmjs.com/cli/v8/configuring-npm/package-json#peerdependencies) on `@raycast/api`. This means that a certain version of `utils` will require a version above a certain version of `api`. `npm` will warn you if that is not the case. [](https://developers.raycast.com/utilities/getting-started#changelog) Changelog ------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/utilities/getting-started#v2.2.5) v2.2.5 * Fixed an issue where `useSql` would not properly show the permission priming screen ### [](https://developers.raycast.com/utilities/getting-started#v2.2.4) v2.2.4 * Fixed an issue where an avatar's initials wouldn't be centered ### [](https://developers.raycast.com/utilities/getting-started#v2.2.3) v2.2.3 * Fixed an issue with `useSQL` on Windows where the query would refuse to be executed because the database is locked ### [](https://developers.raycast.com/utilities/getting-started#v2.2.2) v2.2.2 * Fix `useCachedState` to preserve Date objects more precisely. ### [](https://developers.raycast.com/utilities/getting-started#v2.2.1) v2.2.1 * Fix compiled file to actually make `useSQL` and `executeSQL` work on Windows. ### [](https://developers.raycast.com/utilities/getting-started#v2.2.0) v2.2.0 * Make `useSQL` and `executeSQL` work on Windows. ### [](https://developers.raycast.com/utilities/getting-started#v2.1.1) v2.1.1 * Fix the default size of `getFavicon`. ### [](https://developers.raycast.com/utilities/getting-started#v2.1.0) v2.1.0 * `getFavicon` will now respect the user's setting for the favicon provider. Note that the `Apple` provider isn't supported since it relies on a native API. ### [](https://developers.raycast.com/utilities/getting-started#v2.0.1) v2.0.1 * Fix types for ESM extensions ### [](https://developers.raycast.com/utilities/getting-started#v2.0.0) v2.0.0 * The library can now be tree-shaken, reducing its size considerably. * When using `usePromise` and mutating the data with an optimistic update before it is fetched, the current fetch will be aborted to avoid a race condition. * Add a new [`runPowerShellScript`](https://developers.raycast.com/utilities/functions/runpowershellscript) function. ### [](https://developers.raycast.com/utilities/getting-started#v1.19.1) v1.19.1 * Fixed an issue where arguments weren't passed to `withCache`. ### [](https://developers.raycast.com/utilities/getting-started#v1.19.0) v1.19.0 * Add a new [`withCache`](https://developers.raycast.com/utilities/functions/withcache) function. ### [](https://developers.raycast.com/utilities/getting-started#v1.18.1) v1.18.1 * Fixed an issue where setting `timeout` to `0` in `runAppleScript` would not work. ### [](https://developers.raycast.com/utilities/getting-started#v1.18.0) v1.18.0 * Add a new [\`executeSQL](https://developers.raycast.com/utilities/functions/executesql) function. ### [](https://developers.raycast.com/utilities/getting-started#v1.17.0) v1.17.0 * Add a new [`createDeeplink`](https://developers.raycast.com/utilities/functions/createdeeplink) function. ### [](https://developers.raycast.com/utilities/getting-started#v1.16.5) v1.16.5 * Fixed the bug where `failureToastOptions` did not apply for `useExec` and `useStreamJSON` hooks. ### [](https://developers.raycast.com/utilities/getting-started#v1.16.4) v1.16.4 * Avoid throwing an error when `useFetch` can't parse the `Content-Type` header of the response. ### [](https://developers.raycast.com/utilities/getting-started#v1.16.3) v1.16.3 * Fix an issue where `URLSearchParams` couldn't be passed as an option to `useFetch` or `useCachedPromise`, causing extensions to crash. ### [](https://developers.raycast.com/utilities/getting-started#v1.16.2) v1.16.2 * Fixed the refresh token flow to log out the user instead of throwing an error. ### [](https://developers.raycast.com/utilities/getting-started#v1.16.1) v1.16.1 * Fixed an issue where `bodyEncoding` wasn't properly used in OAuthService. ### [](https://developers.raycast.com/utilities/getting-started#v1.16.0) v1.16.0 * Add a `failureToastOptions` prop to `useFetch`, `useCachedPromise`, and `usePromise` to make it possible to customize the error displayed instead of a generic "Failed to fetch latest data". ### [](https://developers.raycast.com/utilities/getting-started#v1.15.0) v1.15.0 * Add [`useLocalStorage`](https://developers.raycast.com/utilities/react-hooks/uselocalstorage) hook. ### [](https://developers.raycast.com/utilities/getting-started#v1.14.0) v1.14.0 * Add [`useStreamJSON`](https://developers.raycast.com/utilities/react-hooks/usestreamjson) hook. ### [](https://developers.raycast.com/utilities/getting-started#v1.13.6) v1.13.6 * Updated `useFetch`'s `mapResult` type to allow returning `cursor` in addition to `data` and `hasMore`. ### [](https://developers.raycast.com/utilities/getting-started#v1.13.5) v1.13.5 * Extended `PaginationOptions` with `cursor`. ### [](https://developers.raycast.com/utilities/getting-started#v1.13.4) v1.13.4 * Fixed non-paginated version of `useFetch` not being re-run when `url` changes. ### [](https://developers.raycast.com/utilities/getting-started#v1.13.3) v1.13.3 * Fixed `optimisticUpdate` not working when paginating beyond the first page when using `useCachedPromise` or other hooks that build on top of it.. * Fixed `useFetch` type requiring `mapResult` for non-paginated overload. ### [](https://developers.raycast.com/utilities/getting-started#v1.13.2) v1.13.2 * Added default OAuth URLs for Google, Jira, and Zoom ### [](https://developers.raycast.com/utilities/getting-started#v1.13.1) v1.13.1 * Fixed `useFetch` type for non-paginated overload. ### [](https://developers.raycast.com/utilities/getting-started#v1.13.0) v1.13.0 * Added pagination support to `usePromise`, `useCachedPromise` and `useFetch`. ### [](https://developers.raycast.com/utilities/getting-started#v1.12.5) v1.12.5 * Add string array support for OAuth scope (Thanks @tonka3000!). ### [](https://developers.raycast.com/utilities/getting-started#v1.12.4) v1.12.4 * Add `tokenResponseParser` and `tokenRefreshResponseParser` in the options of `OAuthService`. * Fix built-in Slack OAuthServices. ### [](https://developers.raycast.com/utilities/getting-started#v1.12.3) v1.12.3 * Fixed bodyEncoding for some built-in OAuthServices. ### [](https://developers.raycast.com/utilities/getting-started#v1.12.2) v1.12.2 * Fixed types for `OAuthService.slack`. ### [](https://developers.raycast.com/utilities/getting-started#v1.12.1) v1.12.1 * Fixed the refresh flow of `OAuthService` that would return outdated tokens. ### [](https://developers.raycast.com/utilities/getting-started#v1.12.0) v1.12.0 * Removed some default OAuth clientIDs that could not work with generic scopes. * Fixed `withAccessToken` when used in no-view commands. ### [](https://developers.raycast.com/utilities/getting-started#v1.11.1) v1.11.1 * Fixed Google OAuth configuration. ### [](https://developers.raycast.com/utilities/getting-started#v1.11.0) v1.11.0 * Added the [OAuth utils](https://developers.raycast.com/utilities/oauth) . ### [](https://developers.raycast.com/utilities/getting-started#v1.10.1) v1.10.1 * Fix an issue where the values passed to the `reset` function of the `useForm` hook wouldn't be respected. ### [](https://developers.raycast.com/utilities/getting-started#v1.10.0) v1.10.0 * Add a new [`showFailureToast`](https://developers.raycast.com/utilities/functions/showfailuretoast) function. ### [](https://developers.raycast.com/utilities/getting-started#v1.9.1) v1.9.1 * Fix an issue where `useForm`'s `reset` function would not reset the value of some fields (which defeats its purpose...) ### [](https://developers.raycast.com/utilities/getting-started#v1.9.0) v1.9.0 * Add a new [`useFrecencySorting`](https://developers.raycast.com/utilities/react-hooks/usefrecencysorting) hook. * Change the default `options.timeout` of `useExec` to 10s. ### [](https://developers.raycast.com/utilities/getting-started#v1.8.0) v1.8.0 * Add a new [`runAppleScript`](https://developers.raycast.com/utilities/functions/runapplescript) function. * Change the default `options.timeout` of `useExec` to 10s. ### [](https://developers.raycast.com/utilities/getting-started#v1.7.1) v1.7.1 Change the signature of [`getProgressIcon`](https://developers.raycast.com/utilities/icons/getprogressicon) to accept a `Color` in addition to a string for the `options.background`. ### [](https://developers.raycast.com/utilities/getting-started#v1.7.0) v1.7.0 Change the signature of [`getProgressIcon`](https://developers.raycast.com/utilities/icons/getprogressicon) to accept a `Color` in addition to a string for the `color`. ### [](https://developers.raycast.com/utilities/getting-started#v1.6.0) v1.6.0 Added the [`useAI`](https://developers.raycast.com/utilities/react-hooks/useai) hook. ### [](https://developers.raycast.com/utilities/getting-started#v1.4.0) v1.4.0 Added the [`useSQL`](https://developers.raycast.com/utilities/react-hooks/usesql) hook. ### [](https://developers.raycast.com/utilities/getting-started#v1.3.1) v1.3.1 * Added the `reset` method to `useForm`. ### [](https://developers.raycast.com/utilities/getting-started#v1.3.0) v1.3.0 * Added the `focus` method to `useForm`. * Added the `input` option to `useExec`. ### [](https://developers.raycast.com/utilities/getting-started#v1.2.0) v1.2.0 Added [`useExec`](https://developers.raycast.com/utilities/react-hooks/useexec) and [`useForm`](https://developers.raycast.com/utilities/react-hooks/useform) hooks. ### [](https://developers.raycast.com/utilities/getting-started#v1.1.0) v1.1.0 Added [`getFavicon`](https://developers.raycast.com/utilities/icons/getfavicon) method. ### [](https://developers.raycast.com/utilities/getting-started#v1.0.0) v1.0.0 First release of the utilities. [PreviousWindow Management](https://developers.raycast.com/api-reference/window-management) [NextFunctions](https://developers.raycast.com/utilities/functions) Last updated 1 month ago * [Installation](https://developers.raycast.com/utilities/getting-started#installation) * [Changelog](https://developers.raycast.com/utilities/getting-started#changelog) * [v2.2.5](https://developers.raycast.com/utilities/getting-started#v2.2.5) * [v2.2.4](https://developers.raycast.com/utilities/getting-started#v2.2.4) * [v2.2.3](https://developers.raycast.com/utilities/getting-started#v2.2.3) * [v2.2.2](https://developers.raycast.com/utilities/getting-started#v2.2.2) * [v2.2.1](https://developers.raycast.com/utilities/getting-started#v2.2.1) * [v2.2.0](https://developers.raycast.com/utilities/getting-started#v2.2.0) * [v2.1.1](https://developers.raycast.com/utilities/getting-started#v2.1.1) * [v2.1.0](https://developers.raycast.com/utilities/getting-started#v2.1.0) * [v2.0.1](https://developers.raycast.com/utilities/getting-started#v2.0.1) * [v2.0.0](https://developers.raycast.com/utilities/getting-started#v2.0.0) * [v1.19.1](https://developers.raycast.com/utilities/getting-started#v1.19.1) * [v1.19.0](https://developers.raycast.com/utilities/getting-started#v1.19.0) * [v1.18.1](https://developers.raycast.com/utilities/getting-started#v1.18.1) * [v1.18.0](https://developers.raycast.com/utilities/getting-started#v1.18.0) * [v1.17.0](https://developers.raycast.com/utilities/getting-started#v1.17.0) * [v1.16.5](https://developers.raycast.com/utilities/getting-started#v1.16.5) * [v1.16.4](https://developers.raycast.com/utilities/getting-started#v1.16.4) * [v1.16.3](https://developers.raycast.com/utilities/getting-started#v1.16.3) * [v1.16.2](https://developers.raycast.com/utilities/getting-started#v1.16.2) * [v1.16.1](https://developers.raycast.com/utilities/getting-started#v1.16.1) * [v1.16.0](https://developers.raycast.com/utilities/getting-started#v1.16.0) * [v1.15.0](https://developers.raycast.com/utilities/getting-started#v1.15.0) * [v1.14.0](https://developers.raycast.com/utilities/getting-started#v1.14.0) * [v1.13.6](https://developers.raycast.com/utilities/getting-started#v1.13.6) * [v1.13.5](https://developers.raycast.com/utilities/getting-started#v1.13.5) * [v1.13.4](https://developers.raycast.com/utilities/getting-started#v1.13.4) * [v1.13.3](https://developers.raycast.com/utilities/getting-started#v1.13.3) * [v1.13.2](https://developers.raycast.com/utilities/getting-started#v1.13.2) * [v1.13.1](https://developers.raycast.com/utilities/getting-started#v1.13.1) * [v1.13.0](https://developers.raycast.com/utilities/getting-started#v1.13.0) * [v1.12.5](https://developers.raycast.com/utilities/getting-started#v1.12.5) * [v1.12.4](https://developers.raycast.com/utilities/getting-started#v1.12.4) * [v1.12.3](https://developers.raycast.com/utilities/getting-started#v1.12.3) * [v1.12.2](https://developers.raycast.com/utilities/getting-started#v1.12.2) * [v1.12.1](https://developers.raycast.com/utilities/getting-started#v1.12.1) * [v1.12.0](https://developers.raycast.com/utilities/getting-started#v1.12.0) * [v1.11.1](https://developers.raycast.com/utilities/getting-started#v1.11.1) * [v1.11.0](https://developers.raycast.com/utilities/getting-started#v1.11.0) * [v1.10.1](https://developers.raycast.com/utilities/getting-started#v1.10.1) * [v1.10.0](https://developers.raycast.com/utilities/getting-started#v1.10.0) * [v1.9.1](https://developers.raycast.com/utilities/getting-started#v1.9.1) * [v1.9.0](https://developers.raycast.com/utilities/getting-started#v1.9.0) * [v1.8.0](https://developers.raycast.com/utilities/getting-started#v1.8.0) * [v1.7.1](https://developers.raycast.com/utilities/getting-started#v1.7.1) * [v1.7.0](https://developers.raycast.com/utilities/getting-started#v1.7.0) * [v1.6.0](https://developers.raycast.com/utilities/getting-started#v1.6.0) * [v1.4.0](https://developers.raycast.com/utilities/getting-started#v1.4.0) * [v1.3.1](https://developers.raycast.com/utilities/getting-started#v1.3.1) * [v1.3.0](https://developers.raycast.com/utilities/getting-started#v1.3.0) * [v1.2.0](https://developers.raycast.com/utilities/getting-started#v1.2.0) * [v1.1.0](https://developers.raycast.com/utilities/getting-started#v1.1.0) * [v1.0.0](https://developers.raycast.com/utilities/getting-started#v1.0.0) Copy npm install --save @raycast/utils --- # useStreamJSON | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/react-hooks/usestreamjson.md) . Hook which takes a `http://`, `https://` or `file:///` URL pointing to a JSON resource, caches it to the command's support folder, and streams through its content. Useful when dealing with large JSON arrays which would be too big to fit in the command's memory. [](https://developers.raycast.com/utilities/react-hooks/usestreamjson#signature) Signature ----------------------------------------------------------------------------------------------- Copy export function useStreamJSON( url: RequestInfo, options: RequestInit & { filter?: (item: T) => boolean; transform?: (item: any) => T; pageSize?: number; initialData?: U; keepPreviousData?: boolean; execute?: boolean; onError?: (error: Error) => void; onData?: (data: T) => void; onWillExecute?: (args: [string, RequestInit]) => void; failureToastOptions?: Partial>; }, ): AsyncState> & { revalidate: () => void; }; ### [](https://developers.raycast.com/utilities/react-hooks/usestreamjson#arguments) Arguments * `url` - The [`RequestInfo`](https://github.com/nodejs/undici/blob/v5.7.0/types/fetch.d.ts#L12) describing the resource that needs to be fetched. Strings starting with `http://`, `https://` and `Request` objects will use `fetch`, while strings starting with `file:///` will be copied to the cache folder. With a few options: * `options` extends [`RequestInit`](https://github.com/nodejs/undici/blob/v5.7.0/types/fetch.d.ts#L103-L117) allowing you to specify a body, headers, etc. to apply to the request. * `options.pageSize` the amount of items to fetch at a time. By default, 20 will be used * `options.dataPath` is a string or regular expression informing the hook that the array (or arrays) of data you want to stream through is wrapped inside one or multiple objects, and it indicates the path it needs to take to get to it. * `options.transform` is a function called with each top-level object encountered while streaming. If the function returns an array, the hook will end up streaming through its children, and each array item will be passed to `options.filter`. If the function returns something other than an array, _it_ will be passed to `options.filter`. Note that the hook will revalidate every time the filter function changes, so you need to use [useCallback](https://react.dev/reference/react/useCallback) to make sure it only changes when it needs to. * `options.filter` is a function called with each object encountered while streaming. If it returns `true`, the object will be kept, otherwise it will be discarded. Note that the hook will revalidate every time the filter function changes, so you need to use [useCallback](https://react.dev/reference/react/useCallback) to make sure it only changes when it needs to. Including the [useCachedPromise](https://developers.raycast.com/utilities/react-hooks/usecachedpromise) 's options: * `options.keepPreviousData` is a boolean to tell the hook to keep the previous results instead of returning the initial value if there aren't any in the cache for the new arguments. This is particularly useful when used for data for a List to avoid flickering. Including the [useCachedState](https://developers.raycast.com/utilities/react-hooks/usecachedstate) 's options: * `options.initialData` is the initial value of the state if there aren't any in the Cache yet. Including the [usePromise](https://developers.raycast.com/utilities/react-hooks/usepromise) 's options: * `options.execute` is a boolean to indicate whether to actually execute the function or not. This is useful for cases where one of the function's arguments depends on something that might not be available right away (for example, depends on some user inputs). Because React requires every hook to be defined on the render, this flag enables you to define the hook right away but wait until you have all the arguments ready to execute the function. * `options.onError` is a function called when an execution fails. By default, it will log the error and show a generic failure toast with an action to retry. * `options.onData` is a function called when an execution succeeds. * `options.onWillExecute` is a function called when an execution will start. * `options.failureToastOptions` are the options to customize the title, message, and primary action of the failure toast. ### [](https://developers.raycast.com/utilities/react-hooks/usestreamjson#return) Return Returns an object with the [AsyncState](https://developers.raycast.com/utilities/react-hooks/usestreamjson#asyncstate) corresponding to the execution of the fetch as well as a couple of methods to manipulate it. * `data`, `error`, `isLoading` - see [AsyncState](https://developers.raycast.com/utilities/react-hooks/usestreamjson#asyncstate) . * `pagination` - the pagination object that Raycast [`List`s](https://developers.raycast.com/api-reference/user-interface/list#props) and [`Grid`s](https://developers.raycast.com/api-reference/user-interface/grid#props) expect. * `revalidate` is a method to manually call the function with the same arguments again. * `mutate` is a method to wrap an asynchronous update and gives some control over how the hook's data should be updated while the update is going through. By default, the data will be revalidated (eg. the function will be called again) after the update is done. See [Mutation and Optimistic Updates](https://developers.raycast.com/utilities/react-hooks/usestreamjson#mutation-and-optimistic-updates) for more information. [](https://developers.raycast.com/utilities/react-hooks/usestreamjson#example) Example ------------------------------------------------------------------------------------------- [](https://developers.raycast.com/utilities/react-hooks/usestreamjson#mutation-and-optimistic-updates) Mutation and Optimistic Updates ------------------------------------------------------------------------------------------------------------------------------------------- In an optimistic update, the UI behaves as though a change was successfully completed before receiving confirmation from the server that it was - it is being optimistic that it will eventually get the confirmation rather than an error. This allows for a more responsive user experience. You can specify an `optimisticUpdate` function to mutate the data in order to reflect the change introduced by the asynchronous update. When doing so, you can specify a `rollbackOnError` function to mutate back the data if the asynchronous update fails. If not specified, the data will be automatically rolled back to its previous value (before the optimistic update). [](https://developers.raycast.com/utilities/react-hooks/usestreamjson#types) Types --------------------------------------------------------------------------------------- ### [](https://developers.raycast.com/utilities/react-hooks/usestreamjson#asyncstate) AsyncState An object corresponding to the execution state of the function. [PrevioususeFrecencySorting](https://developers.raycast.com/utilities/react-hooks/usefrecencysorting) [NextuseLocalStorage](https://developers.raycast.com/utilities/react-hooks/uselocalstorage) Last updated 1 year ago * [Signature](https://developers.raycast.com/utilities/react-hooks/usestreamjson#signature) * [Arguments](https://developers.raycast.com/utilities/react-hooks/usestreamjson#arguments) * [Return](https://developers.raycast.com/utilities/react-hooks/usestreamjson#return) * [Example](https://developers.raycast.com/utilities/react-hooks/usestreamjson#example) * [Mutation and Optimistic Updates](https://developers.raycast.com/utilities/react-hooks/usestreamjson#mutation-and-optimistic-updates) * [Types](https://developers.raycast.com/utilities/react-hooks/usestreamjson#types) * [AsyncState](https://developers.raycast.com/utilities/react-hooks/usestreamjson#asyncstate) Copy import { Action, ActionPanel, List, environment } from "@raycast/api"; import { useStreamJSON } from "@raycast/utils"; import { join } from "path"; import { useCallback, useState } from "react"; type Formula = { name: string; desc?: string }; export default function Main(): React.JSX.Element { const [searchText, setSearchText] = useState(""); const formulaFilter = useCallback( (item: Formula) => { if (!searchText) return true; return item.name.toLocaleLowerCase().includes(searchText); }, [searchText], ); const formulaTransform = useCallback((item: any): Formula => { return { name: item.name, desc: item.desc }; }, []); const { data, isLoading, pagination } = useStreamJSON("https://formulae.brew.sh/api/formula.json", { initialData: [] as Formula[], pageSize: 20, filter: formulaFilter, transform: formulaTransform }); return ( {data.map((d) => ( ))} ); } Copy import { Action, ActionPanel, List, environment } from "@raycast/api"; import { useStreamJSON } from "@raycast/utils"; import { join } from "path"; import { useCallback, useState } from "react"; import { setTimeout } from "timers/promises"; type Formula = { name: string; desc?: string }; export default function Main(): React.JSX.Element { const [searchText, setSearchText] = useState(""); const formulaFilter = useCallback( (item: Formula) => { if (!searchText) return true; return item.name.toLocaleLowerCase().includes(searchText); }, [searchText], ); const formulaTransform = useCallback((item: any): Formula => { return { name: item.name, desc: item.desc }; }, []); const { data, isLoading, mutate, pagination } = useStreamJSON("https://formulae.brew.sh/api/formula.json", { initialData: [] as Formula[], pageSize: 20, filter: formulaFilter, transform: formulaTransform, }); return ( {data.map((d) => ( { mutate(setTimeout(1000), { optimisticUpdate: () => { return [d]; }, }); }} /> } /> ))} ); } Copy // Initial State { isLoading: true, // or `false` if `options.execute` is `false` data: undefined, error: undefined } // Success State { isLoading: false, data: T, error: undefined } // Error State { isLoading: false, data: undefined, error: Error } // Reloading State { isLoading: true, data: T | undefined, error: Error | undefined } --- # useExec | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/react-hooks/useexec.md) . Hook that executes a command and returns the [AsyncState](https://developers.raycast.com/utilities/react-hooks/useexec#asyncstate) corresponding to the execution of the command. It follows the `stale-while-revalidate` cache invalidation strategy popularized by [HTTP RFC 5861](https://tools.ietf.org/html/rfc5861) . `useExec` first returns the data from cache (stale), then executes the command (revalidate), and finally comes with the up-to-date data again. The last value will be kept between command runs. [](https://developers.raycast.com/utilities/react-hooks/useexec#signature) Signature ----------------------------------------------------------------------------------------- There are two ways to use the hook. The first one should be preferred when executing a single file. The file and its arguments don't have to be escaped. Copy function useExec( file: string, arguments: string[], options?: { shell?: boolean | string; stripFinalNewline?: boolean; cwd?: string; env?: NodeJS.ProcessEnv; encoding?: BufferEncoding | "buffer"; input?: string | Buffer; timeout?: number; parseOutput?: ParseExecOutputHandler; initialData?: U; keepPreviousData?: boolean; execute?: boolean; onError?: (error: Error) => void; onData?: (data: T) => void; onWillExecute?: (args: string[]) => void; failureToastOptions?: Partial>; } ): AsyncState & { revalidate: () => void; mutate: MutatePromise; }; The second one can be used to execute more complex commands. The file and arguments are specified in a single `command` string. For example, `useExec('echo', ['Raycast'])` is the same as `useExec('echo Raycast')`. If the file or an argument contains spaces, they must be escaped with backslashes. This matters especially if `command` is not a constant but a variable, for example with `environment.supportPath` or `process.cwd()`. Except for spaces, no escaping/quoting is needed. The `shell` option must be used if the command uses shell-specific features (for example, `&&` or `||`), as opposed to being a simple file followed by its arguments. ### [](https://developers.raycast.com/utilities/react-hooks/useexec#arguments) Arguments * `file` is the path to the file to execute. * `arguments` is an array of strings to pass as arguments to the file. or * `command` is the string to execute. With a few options: * `options.shell` is a boolean or a string to tell whether to run the command inside of a shell or not. If `true`, uses `/bin/sh`. A different shell can be specified as a string. The shell should understand the `-c` switch. We recommend against using this option since it is: * not cross-platform, encouraging shell-specific syntax. * slower, because of the additional shell interpretation. * unsafe, potentially allowing command injection. * `options.stripFinalNewline` is a boolean to tell the hook to strip the final newline character from the output. By default, it will. * `options.cwd` is a string to specify the current working directory of the child process. By default, it will be `process.cwd()`. * `options.env` is a key-value pairs to set as the environment of the child process. It will extend automatically from `process.env`. * `options.encoding` is a string to specify the character encoding used to decode the `stdout` and `stderr` output. If set to `"buffer"`, then `stdout` and `stderr` will be a `Buffer` instead of a string. * `options.input` is a string or a Buffer to write to the `stdin` of the file. * `options.timeout` is a number. If greater than `0`, the parent will send the signal `SIGTERM` if the child runs longer than timeout milliseconds. By default, the execution will timeout after 10000ms (eg. 10s). * `options.parseOutput` is a function that accepts the output of the child process as an argument and returns the data the hooks will return - see [ParseExecOutputHandler](https://developers.raycast.com/utilities/react-hooks/useexec#parseexecoutputhandler) . By default, the hook will return `stdout`. Including the [useCachedPromise](https://developers.raycast.com/utilities/react-hooks/usecachedpromise) 's options: * `options.keepPreviousData` is a boolean to tell the hook to keep the previous results instead of returning the initial value if there aren't any in the cache for the new arguments. This is particularly useful when used for data for a List to avoid flickering. See [Argument dependent on user input](https://developers.raycast.com/utilities/react-hooks/useexec#argument-dependent-on-user-input) for more information. Including the [useCachedState](https://developers.raycast.com/utilities/react-hooks/usecachedstate) 's options: * `options.initialData` is the initial value of the state if there aren't any in the Cache yet. Including the [usePromise](https://developers.raycast.com/utilities/react-hooks/usepromise) 's options: * `options.execute` is a boolean to indicate whether to actually execute the function or not. This is useful for cases where one of the function's arguments depends on something that might not be available right away (for example, depends on some user inputs). Because React requires every hook to be defined on the render, this flag enables you to define the hook right away but wait until you have all the arguments ready to execute the function. * `options.onError` is a function called when an execution fails. By default, it will log the error and show a generic failure toast with an action to retry. * `options.onData` is a function called when an execution succeeds. * `options.onWillExecute` is a function called when an execution will start. * `options.failureToastOptions` are the options to customize the title, message, and primary action of the failure toast. ### [](https://developers.raycast.com/utilities/react-hooks/useexec#return) Return Returns an object with the [AsyncState](https://developers.raycast.com/utilities/react-hooks/useexec#asyncstate) corresponding to the execution of the command as well as a couple of methods to manipulate it. * `data`, `error`, `isLoading` - see [AsyncState](https://developers.raycast.com/utilities/react-hooks/useexec#asyncstate) . * `revalidate` is a method to manually call the function with the same arguments again. * `mutate` is a method to wrap an asynchronous update and gives some control over how the `useFetch`'s data should be updated while the update is going through. By default, the data will be revalidated (eg. the function will be called again) after the update is done. See [Mutation and Optimistic Updates](https://developers.raycast.com/utilities/react-hooks/useexec#mutation-and-optimistic-updates) for more information. [](https://developers.raycast.com/utilities/react-hooks/useexec#example) Example ------------------------------------------------------------------------------------- [](https://developers.raycast.com/utilities/react-hooks/useexec#argument-dependent-on-user-input) Argument dependent on user input --------------------------------------------------------------------------------------------------------------------------------------- By default, when an argument passed to the hook changes, the function will be executed again and the cache's value for those arguments will be returned immediately. This means that in the case of new arguments that haven't been used yet, the initial data will be returned. This behaviour can cause some flickering (initial data -> fetched data -> arguments change -> initial data -> fetched data, etc.). To avoid that, we can set `keepPreviousData` to `true` and the hook will keep the latest fetched data if the cache is empty for the new arguments (initial data -> fetched data -> arguments change -> fetched data). When passing a user input to a command, be very careful about using the `shell` option as it could be potentially dangerous. [](https://developers.raycast.com/utilities/react-hooks/useexec#mutation-and-optimistic-updates) Mutation and Optimistic Updates ------------------------------------------------------------------------------------------------------------------------------------- In an optimistic update, the UI behaves as though a change was successfully completed before receiving confirmation from the server that it was - it is being optimistic that it will eventually get the confirmation rather than an error. This allows for a more responsive user experience. You can specify an `optimisticUpdate` function to mutate the data in order to reflect the change introduced by the asynchronous update. When doing so, you can specify a `rollbackOnError` function to mutate back the data if the asynchronous update fails. If not specified, the data will be automatically rolled back to its previous value (before the optimistic update). [](https://developers.raycast.com/utilities/react-hooks/useexec#types) Types --------------------------------------------------------------------------------- ### [](https://developers.raycast.com/utilities/react-hooks/useexec#asyncstate) AsyncState An object corresponding to the execution state of the function. ### [](https://developers.raycast.com/utilities/react-hooks/useexec#mutatepromise) MutatePromise A method to wrap an asynchronous update and gives some control about how the `useFetch`'s data should be updated while the update is going through. ### [](https://developers.raycast.com/utilities/react-hooks/useexec#parseexecoutputhandler) ParseExecOutputHandler A function that accepts the output of the child process as an argument and returns the data the hooks will return. [PrevioususeForm](https://developers.raycast.com/utilities/react-hooks/useform) [NextuseSQL](https://developers.raycast.com/utilities/react-hooks/usesql) Last updated 1 year ago * [Signature](https://developers.raycast.com/utilities/react-hooks/useexec#signature) * [Arguments](https://developers.raycast.com/utilities/react-hooks/useexec#arguments) * [Return](https://developers.raycast.com/utilities/react-hooks/useexec#return) * [Example](https://developers.raycast.com/utilities/react-hooks/useexec#example) * [Argument dependent on user input](https://developers.raycast.com/utilities/react-hooks/useexec#argument-dependent-on-user-input) * [Mutation and Optimistic Updates](https://developers.raycast.com/utilities/react-hooks/useexec#mutation-and-optimistic-updates) * [Types](https://developers.raycast.com/utilities/react-hooks/useexec#types) * [AsyncState](https://developers.raycast.com/utilities/react-hooks/useexec#asyncstate) * [MutatePromise](https://developers.raycast.com/utilities/react-hooks/useexec#mutatepromise) * [ParseExecOutputHandler](https://developers.raycast.com/utilities/react-hooks/useexec#parseexecoutputhandler) Copy function useExec( command: string, options?: { shell?: boolean | string; stripFinalNewline?: boolean; cwd?: string; env?: NodeJS.ProcessEnv; encoding?: BufferEncoding | "buffer"; input?: string | Buffer; timeout?: number; parseOutput?: ParseExecOutputHandler; initialData?: U; keepPreviousData?: boolean; execute?: boolean; onError?: (error: Error) => void; onData?: (data: T) => void; onWillExecute?: (args: string[]) => void; failureToastOptions?: Partial>; } ): AsyncState & { revalidate: () => void; mutate: MutatePromise; }; Copy import { List } from "@raycast/api"; import { useExec } from "@raycast/utils"; import { cpus } from "os"; import { useMemo } from "react"; const brewPath = cpus()[0].model.includes("Apple") ? "/opt/homebrew/bin/brew" : "/usr/local/bin/brew"; export default function Command() { const { isLoading, data } = useExec(brewPath, ["info", "--json=v2", "--installed"]); const results = useMemo<{ id: string; name: string }[]>(() => JSON.parse(data || "{}").formulae || [], [data]); return ( {results.map((item) => ( ))} ); } Copy import { useState } from "react"; import { Detail, ActionPanel, Action } from "@raycast/api"; import { useFetch } from "@raycast/utils"; export default function Command() { const [searchText, setSearchText] = useState(""); const { isLoading, data } = useExec("brew", ["info", searchText]); return ; } Copy import { Detail, ActionPanel, Action, showToast, Toast } from "@raycast/api"; import { useFetch } from "@raycast/utils"; export default function Command() { const { isLoading, data, revalidate } = useExec("brew", ["info", "--json=v2", "--installed"]); const results = useMemo<{}[]>(() => JSON.parse(data || "[]"), [data]); const installFoo = async () => { const toast = await showToast({ style: Toast.Style.Animated, title: "Installing Foo" }); try { await mutate( // we are calling an API to do something installBrewCask("foo"), { // but we are going to do it on our local data right away, // without waiting for the call to return optimisticUpdate(data) { return data?.concat({ name: "foo", id: "foo" }); }, }, ); // yay, the API call worked! toast.style = Toast.Style.Success; toast.title = "Foo installed"; } catch (err) { // oh, the API call didn't work :( // the data will automatically be rolled back to its previous value toast.style = Toast.Style.Failure; toast.title = "Could not install Foo"; toast.message = err.message; } }; return ( {(data || []).map((item) => ( installFoo()} /> } /> ))} ); } Copy // Initial State { isLoading: true, // or `false` if `options.execute` is `false` data: undefined, error: undefined } // Success State { isLoading: false, data: T, error: undefined } // Error State { isLoading: false, data: undefined, error: Error } // Reloading State { isLoading: true, data: T | undefined, error: Error | undefined } Copy export type MutatePromise = ( asyncUpdate?: Promise, options?: { optimisticUpdate?: (data: T) => T; rollbackOnError?: boolean | ((data: T) => T); shouldRevalidateAfter?: boolean; }, ) => Promise; Copy export type ParseExecOutputHandler = (args: { /** The output of the process on stdout. */ stdout: string | Buffer; // depends on the encoding option /** The output of the process on stderr. */ stderr: string | Buffer; // depends on the encoding option error?: Error | undefined; /** The numeric exit code of the process that was run. */ exitCode: number | null; /** The name of the signal that was used to terminate the process. For example, SIGFPE. */ signal: NodeJS.Signals | null; /** Whether the process timed out. */ timedOut: boolean; /** The command that was run, for logging purposes. */ command: string; /** The options passed to the child process, for logging purposes. */ options?: ExecOptions | undefined; }) => T; --- # useFetch | Raycast API For the complete documentation index, see [llms.txt](https://developers.raycast.com/llms.txt) . This page is also available as [Markdown](https://developers.raycast.com/utilities/react-hooks/usefetch.md) . Hook which fetches the URL and returns the [AsyncState](https://developers.raycast.com/utilities/react-hooks/usefetch#asyncstate) corresponding to the execution of the fetch. It follows the `stale-while-revalidate` cache invalidation strategy popularized by [HTTP RFC 5861](https://tools.ietf.org/html/rfc5861) . `useFetch` first returns the data from cache (stale), then sends the request (revalidate), and finally comes with the up-to-date data again. The last value will be kept between command runs. [](https://developers.raycast.com/utilities/react-hooks/usefetch#signature) Signature ------------------------------------------------------------------------------------------ Copy export function useFetch( url: RequestInfo, options?: RequestInit & { parseResponse?: (response: Response) => Promise; mapResult?: (result: V) => { data: T }; initialData?: U; keepPreviousData?: boolean; execute?: boolean; onError?: (error: Error) => void; onData?: (data: T) => void; onWillExecute?: (args: [string, RequestInit]) => void; failureToastOptions?: Partial>; }, ): AsyncState & { revalidate: () => void; mutate: MutatePromise; }; ### [](https://developers.raycast.com/utilities/react-hooks/usefetch#arguments) Arguments * `url` is the string representation of the URL to fetch. With a few options: * `options` extends [`RequestInit`](https://github.com/nodejs/undici/blob/v5.7.0/types/fetch.d.ts#L103-L117) allowing you to specify a body, headers, etc. to apply to the request. * `options.parseResponse` is a function that accepts the Response as an argument and returns the data the hook will return. By default, the hook will return `response.json()` if the response has a JSON `Content-Type` header or `response.text()` otherwise. * `options.mapResult` is an optional function that accepts whatever `options.parseResponse` returns as an argument, processes the response, and returns an object wrapping the result, i.e. `(response) => { return { data: response> } };`. Including the [useCachedPromise](https://developers.raycast.com/utilities/react-hooks/usecachedpromise) 's options: * `options.keepPreviousData` is a boolean to tell the hook to keep the previous results instead of returning the initial value if there aren't any in the cache for the new arguments. This is particularly useful when used for data for a List to avoid flickering. See [Argument dependent on List search text](https://developers.raycast.com/utilities/react-hooks/usefetch#argument-dependent-on-list-search-text) for more information. Including the [useCachedState](https://developers.raycast.com/utilities/react-hooks/usecachedstate) 's options: * `options.initialData` is the initial value of the state if there aren't any in the Cache yet. Including the [usePromise](https://developers.raycast.com/utilities/react-hooks/usepromise) 's options: * `options.execute` is a boolean to indicate whether to actually execute the function or not. This is useful for cases where one of the function's arguments depends on something that might not be available right away (for example, depends on some user inputs). Because React requires every hook to be defined on the render, this flag enables you to define the hook right away but wait until you have all the arguments ready to execute the function. * `options.onError` is a function called when an execution fails. By default, it will log the error and show a generic failure toast with an action to retry. * `options.onData` is a function called when an execution succeeds. * `options.onWillExecute` is a function called when an execution will start. * `options.failureToastOptions` are the options to customize the title, message, and primary action of the failure toast. ### [](https://developers.raycast.com/utilities/react-hooks/usefetch#return) Return Returns an object with the [AsyncState](https://developers.raycast.com/utilities/react-hooks/usefetch#asyncstate) corresponding to the execution of the fetch as well as a couple of methods to manipulate it. * `data`, `error`, `isLoading` - see [AsyncState](https://developers.raycast.com/utilities/react-hooks/usefetch#asyncstate) . * `revalidate` is a method to manually call the function with the same arguments again. * `mutate` is a method to wrap an asynchronous update and gives some control over how the `useFetch`'s data should be updated while the update is going through. By default, the data will be revalidated (eg. the function will be called again) after the update is done. See [Mutation and Optimistic Updates](https://developers.raycast.com/utilities/react-hooks/usefetch#mutation-and-optimistic-updates) for more information. [](https://developers.raycast.com/utilities/react-hooks/usefetch#example) Example -------------------------------------------------------------------------------------- [](https://developers.raycast.com/utilities/react-hooks/usefetch#argument-dependent-on-list-search-text) Argument dependent on List search text ---------------------------------------------------------------------------------------------------------------------------------------------------- By default, when an argument passed to the hook changes, the function will be executed again and the cache's value for those arguments will be returned immediately. This means that in the case of new arguments that haven't been used yet, the initial data will be returned. This behaviour can cause some flickering (initial data -> fetched data -> arguments change -> initial data -> fetched data, etc.). To avoid that, we can set `keepPreviousData` to `true` and the hook will keep the latest fetched data if the cache is empty for the new arguments (initial data -> fetched data -> arguments change -> fetched data). [](https://developers.raycast.com/utilities/react-hooks/usefetch#mutation-and-optimistic-updates) Mutation and Optimistic Updates -------------------------------------------------------------------------------------------------------------------------------------- In an optimistic update, the UI behaves as though a change was successfully completed before receiving confirmation from the server that it was - it is being optimistic that it will eventually get the confirmation rather than an error. This allows for a more responsive user experience. You can specify an `optimisticUpdate` function to mutate the data in order to reflect the change introduced by the asynchronous update. When doing so, you can specify a `rollbackOnError` function to mutate back the data if the asynchronous update fails. If not specified, the data will be automatically rolled back to its previous value (before the optimistic update). [](https://developers.raycast.com/utilities/react-hooks/usefetch#pagination) Pagination -------------------------------------------------------------------------------------------- When paginating, the hook will only cache the result of the first page. The hook has built-in support for pagination. In order to enable pagination, `url`s type needs to change from `RequestInfo` to a function that receives a [PaginationOptions](https://developers.raycast.com/utilities/react-hooks/usefetch#paginationoptions) argument, and returns a `RequestInfo`. In practice, this means going from to or, if your data source uses cursor-based pagination, you can return a `cursor` alongside `data` and `hasMore`, and the cursor will be passed as an argument the next time the function gets called: You'll notice that, in the second case, the hook returns an additional item: `pagination`. This can be passed to Raycast's `List` or `Grid` components in order to enable pagination. Another thing to notice is that `mapResult`, which is normally optional, is actually required when using pagination. Furthermore, its return type is Every time the URL is fetched, the hook needs to figure out if it should paginate further, or if it should stop, and it uses the `hasMore` for this. In addition to this, the hook also needs `data`, and needs it to be an array, because internally it appends it to a list, thus making sure the `data` that the hook _returns_ always contains the data for all of the pages that have been fetched so far. ### [](https://developers.raycast.com/utilities/react-hooks/usefetch#full-example) Full Example [](https://developers.raycast.com/utilities/react-hooks/usefetch#types) Types ---------------------------------------------------------------------------------- ### [](https://developers.raycast.com/utilities/react-hooks/usefetch#asyncstate) AsyncState An object corresponding to the execution state of the function. ### [](https://developers.raycast.com/utilities/react-hooks/usefetch#mutatepromise) MutatePromise A method to wrap an asynchronous update and gives some control about how the `useFetch`'s data should be updated while the update is going through. ### [](https://developers.raycast.com/utilities/react-hooks/usefetch#paginationoptions) PaginationOptions An object passed to a `PaginatedRequestInfo`, it has two properties: * `page`: 0-indexed, this it's incremented every time the promise resolves, and is reset whenever `revalidate()` is called. * `lastItem`: this is a copy of the last item in the `data` array from the last time the promise was executed. Provided for APIs that implement cursor-based pagination. * `cursor`: this is the `cursor` property returned after the previous execution of `PaginatedPromise`. Useful when working with APIs that provide the next cursor explicitly. [PrevioususeCachedPromise](https://developers.raycast.com/utilities/react-hooks/usecachedpromise) [NextuseForm](https://developers.raycast.com/utilities/react-hooks/useform) Last updated 1 year ago * [Signature](https://developers.raycast.com/utilities/react-hooks/usefetch#signature) * [Arguments](https://developers.raycast.com/utilities/react-hooks/usefetch#arguments) * [Return](https://developers.raycast.com/utilities/react-hooks/usefetch#return) * [Example](https://developers.raycast.com/utilities/react-hooks/usefetch#example) * [Argument dependent on List search text](https://developers.raycast.com/utilities/react-hooks/usefetch#argument-dependent-on-list-search-text) * [Mutation and Optimistic Updates](https://developers.raycast.com/utilities/react-hooks/usefetch#mutation-and-optimistic-updates) * [Pagination](https://developers.raycast.com/utilities/react-hooks/usefetch#pagination) * [Full Example](https://developers.raycast.com/utilities/react-hooks/usefetch#full-example) * [Types](https://developers.raycast.com/utilities/react-hooks/usefetch#types) * [AsyncState](https://developers.raycast.com/utilities/react-hooks/usefetch#asyncstate) * [MutatePromise](https://developers.raycast.com/utilities/react-hooks/usefetch#mutatepromise) * [PaginationOptions](https://developers.raycast.com/utilities/react-hooks/usefetch#paginationoptions) Copy import { Detail, ActionPanel, Action } from "@raycast/api"; import { useFetch } from "@raycast/utils"; export default function Command() { const { isLoading, data, revalidate } = useFetch("https://api.example"); return ( revalidate()} /> } /> ); } Copy import { useState } from "react"; import { List, ActionPanel, Action } from "@raycast/api"; import { useFetch } from "@raycast/utils"; export default function Command() { const [searchText, setSearchText] = useState(""); const { isLoading, data } = useFetch(`https://api.example?q=${searchText}`, { // to make sure the screen isn't flickering when the searchText changes keepPreviousData: true, }); return ( {(data || []).map((item) => ( ))} ); } Copy import { Detail, ActionPanel, Action, showToast, Toast } from "@raycast/api"; import { useFetch } from "@raycast/utils"; export default function Command() { const { isLoading, data, mutate } = useFetch("https://api.example"); const appendFoo = async () => { const toast = await showToast({ style: Toast.Style.Animated, title: "Appending Foo" }); try { await mutate( // we are calling an API to do something fetch("https://api.example/append-foo"), { // but we are going to do it on our local data right away, // without waiting for the call to return optimisticUpdate(data) { return data + "foo"; }, }, ); // yay, the API call worked! toast.style = Toast.Style.Success; toast.title = "Foo appended"; } catch (err) { // oh, the API call didn't work :( // the data will automatically be rolled back to its previous value toast.style = Toast.Style.Failure; toast.title = "Could not append Foo"; toast.message = err.message; } }; return ( appendFoo()} /> } /> ); } Copy const { isLoading, data } = useFetch( "https://api.ycombinator.com/v0.1/companies?" + new URLSearchParams({ q: searchText }).toString(), { mapResult(result: SearchResult) { return { data: result.companies, }; }, keepPreviousData: true, initialData: [], }, ); Copy const { isLoading, data, pagination } = useFetch( (options) => "https://api.ycombinator.com/v0.1/companies?" + new URLSearchParams({ page: String(options.page + 1), q: searchText }).toString(), { mapResult(result: SearchResult) { return { data: result.companies, hasMore: result.page < result.totalPages, }; }, keepPreviousData: true, initialData: [], }, ); Copy const { isLoading, data, pagination } = useFetch( (options) => "https://api.ycombinator.com/v0.1/companies?" + new URLSearchParams({ cursor: options.cursor, q: searchText }).toString(), { mapResult(result: SearchResult) { const { companies, nextCursor } = result; const hasMore = nextCursor !== undefined; return { data: companies, hasMore, cursor: nextCursor, }; }, keepPreviousData: true, initialData: [], }, ); Copy { data: any[], hasMore?: boolean; cursor?: any; } Copy import { Icon, Image, List } from "@raycast/api"; import { useFetch } from "@raycast/utils"; import { useState } from "react"; type SearchResult = { companies: Company[]; page: number; totalPages: number }; type Company = { id: number; name: string; smallLogoUrl?: string }; export default function Command() { const [searchText, setSearchText] = useState(""); const { isLoading, data, pagination } = useFetch( (options) => "https://api.ycombinator.com/v0.1/companies?" + new URLSearchParams({ page: String(options.page + 1), q: searchText }).toString(), { mapResult(result: SearchResult) { return { data: result.companies, hasMore: result.page < result.totalPages, }; }, keepPreviousData: true, initialData: [], }, ); return ( {data.map((company) => ( ))} ); } Copy // Initial State { isLoading: true, // or `false` if `options.execute` is `false` data: undefined, error: undefined } // Success State { isLoading: false, data: T, error: undefined } // Error State { isLoading: false, data: undefined, error: Error } // Reloading State { isLoading: true, data: T | undefined, error: Error | undefined } Copy export type MutatePromise = ( asyncUpdate?: Promise, options?: { optimisticUpdate?: (data: T) => T; rollbackOnError?: boolean | ((data: T) => T); shouldRevalidateAfter?: boolean; }, ) => Promise; Copy export type PaginationOptions = { page: number; lastItem?: T; cursor?: any; }; ---