| name | cupertino |
| description | This skill should be used when working with Apple APIs, iOS/macOS/visionOS development, or Swift language questions. Covers searching Apple developer documentation, looking up SwiftUI views, finding UIKit APIs, reading Apple docs, browsing Swift Evolution proposals, checking Human Interface Guidelines, and exploring Apple sample code. Supports 402 frameworks including SwiftUI, UIKit, Foundation, and Combine via offline search of 277,000+ documentation pages. |
| allowed-tools | Bash(cupertino *) |
Cupertino: Apple Documentation Search
Search 277,000+ Apple developer documentation pages offline. Cupertino is a lexical search engine over Apple's docs, samples, HIG, Swift Evolution, Swift.org, the Swift book, and Swift package metadata. It returns deterministic, citable results, never hallucinations.
Two rules
- Any Apple-related question goes through cupertino first. SwiftUI, UIKit, AppKit, Foundation, Swift language, iOS / macOS / visionOS / tvOS / watchOS APIs, HIG, sample code, Swift Evolution, Swift packages: ask cupertino before answering. Don't reach for training-data memory of Apple APIs; reach for
cupertino search. If the user's question doesn't obviously involve Apple, but mentions a symbol that might be Apple's (e.g., NavigationStack, URLSession, @Observable), query cupertino to confirm before assuming.
- After you draft an answer, verify the code actually exists on Apple AND that it's the right pattern for the job. Two checks, both run against cupertino:
- Existence: for every symbol, method, initializer, modifier, property, or framework name in your code/answer, re-search cupertino to confirm Apple actually ships that exact thing. Check its signature (parameter names, parameter types, return type), availability (which OS versions / which platforms), and deprecation status against the doc cupertino returns. If a name doesn't trace back to a cupertino hit, the API doesn't exist: you hallucinated it. Fix it (find the real name) or remove it.
- Appropriateness: confirm the pattern / tech you used is the canonical / current Apple recommendation for the task. Cupertino indexes both current and deprecated symbols. Don't recommend
UIWebView when WKWebView exists, URLConnection when URLSession exists, Combine when modern Swift Concurrency fits, or UIKit list patterns when SwiftUI List is what the user asked for. Search for the conceptual area ("loading a web view", "displaying a list of items", "background URL session") and read what Apple's doc actually steers people toward. If the user's context is iOS 17+ or Swift 6, prefer the API Apple ships for that era.
Don't ship code that names APIs cupertino can't find, and don't ship patterns Apple's current docs actively steer away from. This "verify before sending" pass is cheap (millisecond search, few-hundred-token cost), catches most hallucinations, and runs in seconds.
Setup
First-time setup (downloads ~2.4GB database):
cupertino setup
If cupertino setup hasn't been run, do that first.
Search strategy
Cupertino does exact lexical matching. You handle the language understanding before calling it.
1. Translate to canonical Apple terms before searching
Users describe things by appearance, by UIKit muscle memory, or with typos. Cupertino indexes Apple's canonical names. Translate first; search second.
Common translations:
| User says | Likely SwiftUI | Likely UIKit | Likely AppKit |
|---|
| search bar / searchbar | searchable modifier | UISearchBar | NSSearchField |
| text field | TextField | UITextField | NSTextField |
| list view / table view | List | UITableView / UICollectionView | NSTableView |
| segmented control | Picker(.segmented) | UISegmentedControl | NSSegmentedControl |
| spinner / loading indicator | ProgressView | UIActivityIndicatorView | NSProgressIndicator |
| alert | .alert modifier | UIAlertController | NSAlert |
| modal / popup | .sheet, .fullScreenCover | present(_:animated:) | NSWindow.beginSheet |
| switch / toggle | Toggle | UISwitch | NSSwitch |
| stepper | Stepper | UIStepper | NSStepper |
| web view | WKWebView (UIKit) | WKWebView | WKWebView |
When you translate, tell the user: "Searching for searchable (SwiftUI equivalent of search bar)."
2. Handle typos and "did you mean" yourself
Cupertino does not fuzzy-match. If the user types searchabe, calling cupertino search "searchabe" will return weak results. You correct the typo first, then search:
searchabe → search for searchable
unviewcontroller → search for UIViewController
tabel view → search for UITableView or List (depending on framework)
Use your knowledge of Apple naming conventions. If unsure, search for both the literal query and your guess; compare results.
3. Infer the framework from context
Use --framework to narrow when the framework is obvious:
- Conversation about SwiftUI views →
--framework swiftui
- Symbol prefix
NS* → --framework appkit
- Symbol prefix
UI* → --framework uikit
- Symbol prefix
MK* → --framework mapkit
- File the user is editing imports a specific framework → use that
If the framework is genuinely ambiguous, search without --framework and disambiguate from results.
4. Prefer current API over deprecated
Apple keeps deprecated symbols indexed. Lead with the current canonical:
UIWebView is deprecated → recommend WKWebView
UISearchDisplayController is deprecated → recommend UISearchController
UITableView for new code → recommend UICollectionView or SwiftUI List
When you mention a deprecated symbol in your answer, flag it.
5. Bare-name ambiguity: use specific function signatures when needed
Bare-name queries can collide with namespaced symbols elsewhere in the index. Common collisions:
searchable → returns CoreSpotlight CSSearchableIndex, not the SwiftUI modifier. Use searchable(text: to find the modifier directly.
View → returns hits across many frameworks; prefer View with --framework swiftui and check the metadata.framework field on each candidate.
- Common protocol names (
Identifiable, Codable) hit the protocol page only when paired with a more specific term.
When a bare-name query returns the wrong thing, try the function-signature form (name(arg1:arg2:) or pair the query with a distinguishing keyword.
6. Recovery when results are weak
If a search returns nothing useful:
- Try a paradigm bridge: if a UIKit name returned nothing in a SwiftUI context, search the SwiftUI canonical (and vice versa).
- Try conceptual phrasing: if
tableview returns weak results, try cupertino search "building list interfaces" or cupertino search "displaying a list of items" to find Apple's conceptual pages. Descriptive queries often surface the right concept page.
- Try the function-signature form:
searchable(text: instead of searchable.
- Always tell the user what you tried: "No direct hit for
searchbar. Retried as searchable(text: (SwiftUI modifier), found 5 results."
Never silently rewrite without telling the user what you did.
Per-source response shapes differ
Filtered searches (--source X) return a per-source dedicated view, not the unified candidates shape. The unified search exists for cross-source ranking; the per-source views are for browsing one source's structured data.
Shapes (stable across v1.0.x):
- default (no
--source): {candidates, contributingSources, question}
--source apple-docs: top-level list of doc objects with availability, framework, id, rank
--source samples: {files: [{filename, path, projectId, rank, snippet}]}
--source hig: {count, query, results: [{title, uri, summary, availability}]}
--source packages: {candidates, contributingSources: ["packages"], question} (matches the unified shape; routes to packages.db)
--source apple-archive / swift-evolution / swift-org / swift-book: source-specific shapes
If you parse JSON, expect different keys per source. The default unified search is the most consistent option when you don't need source-specific fields.
Known limitations
These are gotchas worth knowing so you can route around them:
- Cross-paradigm bridge queries like "swiftui equivalent of UITableView" may return release notes instead of migration guides. Workaround: search both frameworks separately and present the comparison yourself.
- Some descriptive queries miss when phrasing diverges from Apple's wording. If
"how to display loading spinner" misses, try "ProgressView" directly or "loading interface".
6. Migration / cross-paradigm queries
If the user asks "SwiftUI equivalent of UITableView" or mentions migration:
- Search both frameworks
- Look for migration-guide pages (often titled "Migrating from X to Y")
- Present both: the new canonical (e.g.,
List) AND the old symbol the user knows (UITableView)
Citation and verification (do this for every answer)
Cupertino's value is grounding. Use it.
Cite as you go
For every API, framework, or concept you mention in your answer, name the cupertino URI it came from. Example:
Use searchable(text:) (apple-docs://swiftui/view/searchable(text:)) to add a search field to a SwiftUI view. The modifier was introduced in iOS 15.
This costs you almost nothing in tokens (you're already typing the symbol name) and prevents hallucination because you can only cite what you actually retrieved.
Verify before sending
Before finalizing your answer, scan it for every API/symbol you named. Each one must trace back to a URI you got from cupertino. If it doesn't:
- Re-search to confirm it exists:
cupertino search "<symbol>" --format json
- If still no hit, mark it as uncertain in your answer ("I'm less sure about X; couldn't confirm in Apple docs") or remove it
- Never fabricate parameter names, return types, or platform availability
Token-efficient verification
| Pattern | Cost | When to use |
|---|
| Cite as you go (no extra calls) | ~5% overhead | Always |
| Re-search uncertain claims | 1 search call per claim (~500 tokens) | When you mention an API you don't 100% remember |
| Full LLM verify pass | 1.5–2× baseline | High-stakes answers (production code, security) |
| Wrong answer + user correction | 3–5× baseline | Worst case; avoid |
The cite-as-you-go default is essentially free and prevents most hallucinations. Re-search for uncertain claims is cheap. Full verify passes are usually overkill.
Commands
Search Documentation
Search across all sources (apple-docs, samples, hig, swift-evolution, swift-org, swift-book, packages):
cupertino search "SwiftUI View" --format json
cupertino search "SwiftUI View" --format json --limit 5
Filter by source:
cupertino search "async await" --source swift-evolution --format json
cupertino search "NavigationStack" --source apple-docs --format json
cupertino search "button styles" --source samples --format json
cupertino search "button guidelines" --source hig --format json
Filter by framework:
cupertino search "@Observable" --framework swiftui --format json
Read a Document
Retrieve full document content by URI:
cupertino read "apple-docs://swiftui/documentation_swiftui_view" --format json
cupertino read "apple-docs://swiftui/documentation_swiftui_view" --format markdown
List Frameworks
List all indexed frameworks with document counts:
cupertino list-frameworks --format json
List Sample Projects
Browse indexed Apple sample code projects:
cupertino list-samples --format json
cupertino list-samples --framework swiftui --format json
Read Sample Code
Read a sample project or specific file:
cupertino read-sample "foodtrucksampleapp" --format json
cupertino read-sample-file "foodtrucksampleapp" "FoodTruckApp.swift" --format json
Sources
| Source | Description |
|---|
apple-docs | Official Apple documentation (~277,000+ pages indexed in v1.0.2) |
swift-evolution | Swift Evolution proposals |
hig | Human Interface Guidelines |
samples | Apple sample code projects |
swift-org | Swift.org documentation |
swift-book | The Swift Programming Language book |
apple-archive | Legacy guides (Core Animation, Quartz 2D, KVO/KVC) |
packages | Swift package documentation |
Output Formats
All commands support --format with these options:
text - Human-readable output (default for most commands)
json - Structured JSON for parsing (use this when reasoning about results)
markdown - Formatted markdown
Example JSON Output
cupertino search returns:
{
"candidates": [
{
"rank": 1,
"score": 0.91,
"title": "VStack | Apple Developer Documentation",
"identifier": "apple-docs://swiftui/documentation_swiftui_vstack",
"source": "apple-docs",
"metadata": {
"filePath": "https://developer.apple.com/documentation/SwiftUI/VStack",
"framework": "swiftui"
},
"chunk": "VStack | Apple Developer Documentation\n\nA view that arranges...",
"readFullCommand": "cupertino read apple-docs://swiftui/documentation_swiftui_vstack --source apple-docs"
}
],
"contributingSources": ["packages", "samples", "apple-docs", "hig", "swift-evolution"],
"question": "VStack"
}
Use identifier (not uri) with cupertino read. Each candidate carries a readFullCommand field with the exact command pre-built.
cupertino read returns:
{
"id": "...",
"title": "VStack | Apple Developer Documentation",
"url": "https://developer.apple.com/documentation/swiftui/vstack",
"abstract": "A view that arranges its children vertically.",
"overview": "...",
"rawMarkdown": "---\nsource: ...\n...",
"declaration": {"code": "...", "language": "swift"},
"availability": [...],
"codeExamples": [...],
"sections": [...],
"kind": "structure",
"source": "appleWebKit",
"contentHash": "...",
"crawledAt": "2026-05-01T20:50:48Z"
}
Note framework is encoded in the url path, not as a top-level field. The source field on read returns the crawler identifier (appleWebKit), not the cupertino source taxonomy from search.
Tips
- Use
--source to narrow searches to a specific documentation source
- Use
--framework to filter by framework (e.g., swiftui, foundation, uikit)
- Use
--limit to control the number of results returned (default works well; 5–10 is plenty)
- URIs from search results can be used directly with
cupertino read
- Legacy archive guides are excluded from search by default; add
--include-archive to include them
- Code examples in the indexed docs are usually more useful than descriptions for understanding API usage