
Cupertino v0.4.0: HIG Support, Framework Aliases, and Release Engineering Lessons
TL;DR: Human Interface Guidelines support, smarter framework search, and a hard lesson about release engineering.
Why jump from 0.3.4 to 0.4.0? Five issues closed: HIG support (#69), framework aliases (#91, #92), and Swift.org fixes (#93, #94). Enough new functionality to warrant a minor version bump.
What’s New
Human Interface Guidelines Support
Cupertino can now crawl and index Apple’s Human Interface Guidelines:
cupertino fetch --type hig
There’s also a new search_hig MCP tool that lets…

Cupertino v0.4.0: HIG Support, Framework Aliases, and Release Engineering Lessons
TL;DR: Human Interface Guidelines support, smarter framework search, and a hard lesson about release engineering.
Why jump from 0.3.4 to 0.4.0? Five issues closed: HIG support (#69), framework aliases (#91, #92), and Swift.org fixes (#93, #94). Enough new functionality to warrant a minor version bump.
What’s New
Human Interface Guidelines Support
Cupertino can now crawl and index Apple’s Human Interface Guidelines:
cupertino fetch --type hig
There’s also a new search_hig MCP tool that lets AI agents search design guidelines with platform and category filters. When you ask Claude “what are Apple’s recommendations for buttons?”, it can actually look it up instead of guessing from training data.
Everything available via MCP tools is also available via command line:
cupertino search "buttons" --source hig
This is something people might not realize: you can query Cupertino the same way AI does. Every MCP tool has a CLI equivalent. Want to see exactly what Claude sees when it searches? Run the same query yourself. Useful for testing, debugging, or when you just want quick answers without a conversation.
Framework Aliases
Before, searching for “Core Animation” might not find results indexed under “QuartzCore” (the actual import name). Now there are 249 framework aliases in the database:
QuartzCore↔CoreAnimation↔Core AnimationCoreGraphics↔Quartz2D↔Quartz 2D
Search works regardless of which name variant you use.
Swift.org Fixes
The Swift.org crawler was broken. The base URL had changed from docs.swift.org to www.swift.org/documentation/, and the indexer was looking for .md files when the crawler was saving .json files. Fixed.
Why This Matters
Here’s a real example from today. I asked Claude about Apple’s Foundation Models framework - the new on-device ML APIs. Claude’s response:
“The MCP server pulls the complete Foundation Models sample code documentation - straight from Apple’s current docs. No hallucinated API names!”
More examples of documentation you can search:
- FoundationModels - Apple’s new on-device ML framework
- Writing Tools - System-wide AI writing assistance
- Genmoji - Custom emoji generation
- Image Playground - On-device image generation
This is also why Cupertino needs a human touch - it can’t be fully automated. Someone has to notice when Apple adds new frameworks, when URLs change (like Swift.org did), when documentation structures shift. The crawler is automated, but the awareness isn’t.
That’s the whole point: deterministic, up-to-date docs instead of training data guesses.
Token Efficiency
A side benefit: Cupertino is more token-efficient than you’d expect.
Yes, tool results use tokens - documentation goes into context. But:
- Accurate = fewer turns - No hallucination means no correction loop
- Curated content - Returns exactly what’s needed, not web search noise
- Local search is free - No API cost for the search operation itself
- Truncated summaries - Results are summarized; full doc only when you call
read_document
So not zero tokens, but more efficient token use. And no external API costs for search.
The Archive Discovery Problem
Here’s something interesting I discovered while testing. When Claude searched for “CALayer animation”, it got API reference pages - classes, methods, properties. Claude wanted to dig deeper:
“Let me try a more targeted search - something like the layer tree architecture or model/presentation layers that would be covered in the Core Animation Programming Guide.”
Then I suggested searching with source: "apple-archive". Claude’s reaction:
“Now THAT’s the difference! When searching with source: apple-archive, we get the Core Animation Programming Guide and the Animation Types and Timing Programming Guide - the real meat.”
The conceptual deep-dives that explain why things work the way they do.
Modern Apple docs = API reference (the what) Archive docs = Conceptual guides (the why)
The problem? AI agents don’t know to search the archive. It’s an opt-in parameter buried in the tool description.
The Solution: Auto-Surface Archive Teasers
I’m planning to modify search results to automatically hint at archive content:
# Search Results for "CALayer animation"
## Modern Documentation
[1] CALayer - API reference...
[2] CABasicAnimation - API reference...
---
## 📚 Related Archive Guides
**Core Animation Programming Guide** - Layer geometry, animation timing...
> For full archive content, search with `source: "apple-archive"`
This way:
- Modern docs still come first
- AI agents always see archive exists
- They learn how to get more, in context
Only show the archive section if there are relevant results. Same principle could apply to sample code, Swift packages, or any other source.
The Release Process Disaster
Here’s where it gets interesting. I had all the code ready, all the tests passing, and I was ready to ship.
The process seemed simple:
- Bump version in
Constants.swift - Update
README.mdandCHANGELOG.md - Create git tag
- Push tag (triggers GitHub Actions build)
- Upload databases to
cupertino-docs - Update Homebrew formula
What could go wrong?
The Tag Timing Problem
I merged my feature branch, created the tag, pushed it… and then realized I hadn’t committed the version bump to main yet. The tag pointed to a commit where Constants.swift still said 0.3.5.
GitHub Actions dutifully built a beautiful, signed, notarized universal binary… that reported version 0.3.5.
$ cupertino --version
0.3.5
When users ran cupertino setup, it tried to download databases from v0.3.5 instead of v0.4.0. Everything was broken.
The Fix
I had to:
- Delete the tag on GitHub
- Delete the local tag
- Make sure the version bump commit was pushed to
main - Verify the built binary reports correct version before tagging
- Recreate the tag
- Wait for GitHub Actions to rebuild
- Update the Homebrew formula with the new SHA256
The SHA256 Dance
When I first updated the Homebrew formula, I grabbed the SHA256 from the old (broken) binary. After rebuilding, the checksum changed. Users got:
Error: Formula reports different checksum: cf035352...
SHA-256 checksum of downloaded file: 5c5cf7ab...
Another round of updating the tap.
The 11-Step Release Process
After today’s adventures, here’s what the release process actually looks like:
- Update version in
Constants.swift,README.md,CHANGELOG.md - Commit and push to main
- Build locally and verify
--versionmatches - Create and push tag
- Wait for GitHub Actions (~5 min)
- Create GitHub release with notes
- Build locally and install
- Upload databases with
cupertino release - Get new SHA256 from release
- Update Homebrew tap formula
- Verify on fresh machine
That’s 11 steps across 4 repositories. Miss one, and you’re rebuilding everything.
Time for Automation?
I’m seriously considering writing a release script. Swift or Bash?
The pragmatic choice is Bash - it’s just orchestrating CLI commands. But I’m a Swift purist. The cupertino release command already handles database uploads with proper GitHub API integration. Extending it to handle the full workflow feels right.
Something like cupertino release --full that:
- Checks for uncommitted changes
- Verifies version consistency
- Builds and validates
--version - Creates and pushes the tag
- Waits for GitHub Actions
- Uploads databases
- Updates the Homebrew tap
One command. No mistakes. Written in Swift.
Lessons Learned
- Order matters. Commit the version bump before creating the tag.
- Verify before you ship. Build locally and check
--versionbefore tagging. - Document your release process. I now have a detailed
DEPLOYMENT.mdwith warnings. - Automate what hurts. If you make the same mistake twice, write a script.
What’s Next
- Enhanced search results - Auto-surface archive, samples, packages in every search (high priority)
- Release automation -
cupertino release --fullin Swift - Fix setup animations - They’re broken
- Keep crawling - Fresh docs matter
This release taught me a lot. Not just about release engineering, but about how AI agents actually use documentation. The archive discovery problem was a surprise - valuable content hidden behind an opt-in flag that agents don’t know to use.
Building tools for AI is different. You’re not just building for humans who read documentation. You’re building for agents that learn from tool descriptions and in-context hints.
Key discovery: Claude reads tool descriptions once, but reads search results every time. If you want agents to use a feature, put it in the output - not buried in documentation they’ll forget. Every search result is a teaching moment.
Next up: implementing enhanced search results. Once that ships, every search will auto-surface relevant content from archives, samples, and packages - with the exact commands to dig deeper. No more hidden treasure.
Cupertino is an Apple Documentation MCP Server. Install with brew install mihaelamj/tap/cupertino. Check it out at github.com/mihaelamj/cupertino.