TL;DR
- Context: A side project alongside my UX Lead job at a bank. Raycast is my daily tool on Mac, a Spotlight replacement.
- Problem: Raycast’s extension store has over 1,700 entries, zero categories, and 10 results per page.
- What I did: Built a script that pulls data from Raycast’s official repository, categorizes extensions through the OpenAI API, and publishes a ready catalog as a standalone GitHub repo.
- Result: 1,716 extensions across 18 categories, 600 stars and 12 forks. Maintained for ~5 months, now archived.
Diagnosis
Raycast’s extension store has over 1,700 entries and no real way to browse them: no categories, 10 results per page. I could have worked around that with web scraping, but I didn’t want to break the terms of service or depend on something that would break the moment the page layout changed. Instead I found the official GitHub repository where Raycast keeps the data for every extension, forked it, and built a script around it: pull the data, categorize it through GPT, publish a ready catalog as a README.
flowchart TD
subgraph Before["Before"]
A1["Look for an extension<br/>in the Raycast store"] --> A2["No categories,<br/>10 results per page"]
A2 --> A3["Scroll through pages<br/>or guess the exact name"]
end
subgraph After["After"]
B1["Fork raycast/extensions<br/>+ script that merges the data"] --> B2["Categorization<br/>via OpenAI API"]
B2 --> B3["Catalog on GitHub,<br/>18 categories"]
end
classDef good fill:#e6f2ea,stroke:none,color:#1f4d33,rx:14,ry:14
classDef bad fill:#faeaea,stroke:none,color:#5f2626,rx:14,ry:14
classDef accent fill:#27272a,stroke:#3f3f46,stroke-width:1px,color:#fafafa,rx:14,ry:14
class A1,A2,A3 bad
class B1,B2 good
class B3 accent
style Before fill:transparent,stroke:#a1a1aa,stroke-width:1px,rx:14,ry:14
style After fill:transparent,stroke:#a1a1aa,stroke-width:1px,rx:14,ry:14
linkStyle default stroke:#a8a8b3,stroke-width:1.5px
What I did
- Forked the official
raycast/extensionsrepository and wrote a script that merges thepackage.jsonfile from every extension into a single data array. - Categorized the extensions through the OpenAI API: first GPT-3.5-Turbo-0125 (one of the first models with controlled JSON output), later GPT-4-turbo, with a prompt that keeps the model on a fixed list of categories.
- Automated the whole pipeline into essentially one script: sync the fork, detect new extensions against the previous run, categorize, generate the README, publish.
- Published the result as a public GitHub repo: 1,716 extensions across 18 categories.
Results
| Metric | Value |
|---|---|
| Extensions categorized | 1,716 |
| Categories | 18 |
| GitHub stars | 600 |
| Forks | 12 |
| Active maintenance | ~5 months (May–September 2024) |
- 1,716 extensions categorized automatically, with no manual review of each entry.
- 600 stars and 12 forks on GitHub. People actually used it.
- Zero scraping. The entire solution runs on official data from Raycast’s own repository.
- The pipeline ran as one script, not manual work on every update.
The problem
Why is the Raycast extension store hard to browse?
The store page has no developed category system, and a single view shows only 10 extensions at a time. With over 1,700 entries, that means scrolling through dozens of pages or hitting the exact name in search. If you don’t know exactly what you’re looking for, which is often the case when you’re still discovering what Raycast can do, there’s no way to browse it meaningfully.
Why not just scrape the site?
Because that’s a fragile solution sitting right on the edge of the terms of service. The page can change at any point and break the scraper; on top of that, reading data straight from someone else’s frontend, instead of the data that company actually publishes, wasn’t something I was willing to do. The official GitHub repository, where Raycast keeps the package.json for every extension, gave me the same data in a way I could rely on.
My role / scope
- Solo side project, alongside my full-time job as a UX Lead at a bank.
- Designed the whole pipeline and the categorization prompt, wrote the scripts, maintained the repository for ~5 months.
Process
- Researched the data source: instead of scraping the site, I found and forked the official GitHub repository holding data for every extension.
- Iterated on the prompt: a few attempts before the model consistently stuck to the given categories instead of inventing its own.
- Automated it step by step: sync the fork → new folder for the date → diff against the previous run → categorize via API → generate the README → publish.
- Maintained it: 11 commits between May and September 2024, as new extensions appeared.
Key decisions & trade-offs
- Official repo instead of scraping. A slower start (finding the right repository and understanding its structure), but a solution that’s stable and within the rules, instead of one that breaks the first time the site changes.
| Approach | Risk | Decision |
|---|---|---|
| Scraping the Raycast store page | breaks terms of service, fragile against layout changes | rejected |
| Fork of the official GitHub repo | depends on the package.json structure in the repo | chosen |
- Structured JSON output instead of parsing free text. GPT-3.5-Turbo-0125 gave controlled JSON output, so I didn’t need to write a separate parser for the model’s response. This was one of the first times I tested structured output hands-on, before it became standard across most models.
- Honestly: I stopped shipping updates in September 2024. The repo is now archived. Without dedicated time alongside a full-time job, monitoring new extensions and fixing categories stopped scaling.
How it turned out
The repo has 600 stars and 12 forks, but the last commit is from September 2024, and it’s archived today. Raycast’s official store still has no real way to browse by category, only search and a handful of footer links, so the problem I set out to solve still exists. I didn’t keep going because maintaining the categorization alongside a full-time job stopped being worth it. That was a deliberate stop, not a failed project.
What I took away
- Automation isn’t “build it once and done.” Even a well-designed pipeline needs someone to maintain it as the data source keeps growing.
- Choosing a data source is a design decision, not just a technical one. The official repo was slower to start with than scraping, but it wasn’t fragile, and that paid off over 5 months of running.
- Structured output in an LLM saves hours of work. Before JSON mode became standard, testing it hands-on gave me a real feel for when AI actually speeds up work, and when it only looks like it does.