
geotoolbox
GeoToolbox PlaceDescriptor patterns with MapKit integration for location representation, geocoding, and multi-service place identifiers. Use when working with place descriptors, geocoding, or cross-service location data.
- Installs
- 74
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/rshankras/claude-code-apple-skills --skill geotoolbox- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads geotoolbox automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
GeoToolbox and PlaceDescriptor Patterns
Portable location representation using PlaceDescriptor from the GeoToolbox framework. Covers place construction from coordinates, addresses, and MapKit items; forward and reverse geocoding with the new async APIs; and multi-service place identifiers for cross-platform interop.
When This Skill Activates
Use this skill when the user:
- Asks about GeoToolbox or PlaceDescriptor
- Wants to represent a place with coordinates, address, or common name
- Needs to convert between MKMapItem and PlaceDescriptor
- Asks about forward geocoding (address to coordinates) or reverse geocoding (coordinates to address)
- Wants to store or transmit multi-service place identifiers (Apple Maps, Google Maps, etc.)
- Mentions PlaceRepresentation, SupportingPlaceRepresentation, or MKGeocodingRequest
- Asks about portable or interoperable location data structures
Decision Tree
What do you need?
|
+-- Represent a place with coordinates and/or address
| +-- From a known coordinate
| | +-- PlaceRepresentation.coordinate(CLLocationCoordinate2D)
| +-- From a known address string
| | +-- PlaceRepresentation.address(String)
| +-- Both coordinate and address
| | +-- Pass multiple representations to PlaceDescriptor
| +-- From an existing MKMapItem
| +-- PlaceDescriptor(item: MKMapItem)
|
+-- Geocode an address to coordinates
| +-- MKGeocodingRequest(addressString:)
| +-- try await request.mapItems
|
+-- Reverse geocode coordinates to an address
| +-- MKReverseGeocodingRequest(location:)
| +-- try await request.mapItems
|
+-- Attach service identifiers (Apple Maps, Google, etc.)
| +-- SupportingPlaceRepresentation.serviceIdentifiers([String: String])
|
+-- Read place properties
+-- descriptor.coordinate, descriptor.address, descriptor.commonName
+-- descriptor.serviceIdentifier(for: "com.apple.maps")
API Availability
| API | Minimum OS | Import |
|---|---|---|
PlaceDescriptor | iOS 26 / macOS 26 | GeoToolbox |
PlaceRepresentation | iOS 26 / macOS 26 | GeoToolbox |
SupportingPlaceRepresentation | iOS 26 / macOS 26 | GeoToolbox |
MKGeocodingRequest | iOS 26 / macOS 26 | MapKit |
MKReverseGeocodingRequest | iOS 26 / macOS 26 | MapKit |
PlaceDescriptor(item:) | iOS 26 / macOS 26 | GeoToolbox + MapKit |
MKMapItem | iOS 6 / macOS 10.9 | MapKit |
CLLocationCoordinate2D | iOS 2 / macOS 10.6 | CoreLocation |
Quick Start
Create a PlaceDescriptor from Coordinates
import GeoToolbox
import CoreLocation
let coordinate = CLLocationCoordinate2D(latitude: 37.3349, longitude: -122.0090)
let descriptor = PlaceDescriptor(
representations: [.coordinate(coordinate)],
commonName: "Apple Park"
)
// Read back
if let coord = descriptor.coordinate {
print("Lat: \(coord.latitude), Lon: \(coord.longitude)")
}
print(descriptor.commonName ?? "No name")
Create a PlaceDescriptor from an Address
import GeoToolbox
let descriptor = PlaceDescriptor(
representations: [.address("One Apple Park Way, Cupertino, CA 95014")],
commonName: "Apple Park"
)
if let address = descriptor.address {
print("Address: \(address)")
}
Multiple Representations and Service Identifiers
import GeoToolbox
import CoreLocation
let coordinate = CLLocationCoordinate2D(latitude: 37.3349, longitude: -122.0090)
let descriptor = PlaceDescriptor(
representations: [
.coordinate(coordinate),
.address("One Apple Park Way, Cupertino, CA 95014")
],
commonName: "Apple Park",
supportingRepresentations: [
.serviceIdentifiers([
"com.apple.maps": "apple-maps-id-12345",
"com.google.maps": "ChIJ-bfVTh8_j4ARDMPaL2Njo3I"
])
]
)
// Access a specific service identifier
if let appleId = descriptor.serviceIdentifier(for: "com.apple.maps") {
print("Apple Maps ID: \(appleId)")
}
Convert from MKMapItem
import GeoToolbox
import MapKit
func descriptorFromMapItem(_ mapItem: MKMapItem) -> PlaceDescriptor {
PlaceDescriptor(item: mapItem)
}
Forward Geocoding (Address to Coordinates)
import MapKit
func geocodeAddress(_ addressString: String) async throws -> [MKMapItem] {
let request = MKGeocodingRequest(addressString: addressString)
let mapItems = try await request.mapItems
return mapItems
}
// Usage
let items = try await geocodeAddress("One Apple Park Way, Cupertino, CA")
if let first = items.first {
let coord = first.placemark.coordinate
print("Found: \(coord.latitude), \(coord.longitude)")
}
Reverse Geocoding (Coordinates to Address)
import MapKit
import CoreLocation
func reverseGeocode(_ coordinate: CLLocationCoordinate2D) async throws -> [MKMapItem] {
let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
let request = MKReverseGeocodingRequest(location: location)
let mapItems = try await request.mapItems
return mapItems
}
// Usage
let coordinate = CLLocationCoordinate2D(latitude: 37.3349, longitude: -122.0090)
let items = try await reverseGeocode(coordinate)
if let first = items.first {
print("Address: \(first.placemark.title ?? "Unknown")")
}
Full Integration Example
Geocode an address, convert the result to a PlaceDescriptor with service identifiers, and read back all properties:
import GeoToolbox
import MapKit
import CoreLocation
func buildPlaceDescriptor(from addressString: String) async throws -> PlaceDescriptor? {
// Forward geocode
let request = MKGeocodingRequest(addressString: addressString)
let mapItems = try await request.mapItems
guard let mapItem = mapItems.first else { return nil }
// Convert MKMapItem to PlaceDescriptor
var descriptor = PlaceDescriptor(item: mapItem)
// Or build manually with extra data
let coordinate = mapItem.placemark.coordinate
descriptor = PlaceDescriptor(
representations: [
.coordinate(coordinate),
.address(addressString)
],
commonName: mapItem.name,
supportingRepresentations: [
.serviceIdentifiers([
"com.apple.maps": "resolved-id-\(coordinate.latitude)"
])
]
)
return descriptor
}
func displayDescriptor(_ descriptor: PlaceDescriptor) {
if let name = descriptor.commonName {
print("Name: \(name)")
}
if let coord = descriptor.coordinate {
print("Coordinate: \(coord.latitude), \(coord.longitude)")
}
if let address = descriptor.address {
print("Address: \(address)")
}
if let appleId = descriptor.serviceIdentifier(for: "com.apple.maps") {
print("Apple Maps ID: \(appleId)")
}
}
Top Mistakes
| # | Mistake | Problem | Fix |
|---|---|---|---|
| 1 | Importing only MapKit when using PlaceDescriptor | PlaceDescriptor lives in GeoToolbox, not MapKit | Add import GeoToolbox alongside import MapKit |
| 2 | Hardcoding service identifier keys | Service identifier keys are strings; typos cause silent failures | Define constants for service keys like "com.apple.maps" |
| 3 | Not handling geocoding errors | Network or service failures throw errors | Use do/catch or try await with proper error handling |
Patterns
Service Identifier Constants
Define constants to avoid typos in service identifier keys:
// Good -- constants prevent typos
enum PlaceService {
static let appleMaps = "com.apple.maps"
static let googleMaps = "com.google.maps"
static let foursquare = "com.foursquare"
}
if let id = descriptor.serviceIdentifier(for: PlaceService.appleMaps) {
// use id
}
// Bad -- raw string literals are error-prone
if let id = descriptor.serviceIdentifier(for: "com.apple.map") { // typo: "map" not "maps"
// silently nil
}
Nil-Safe Property Access
// Good -- check each optional property
func formatPlace(_ descriptor: PlaceDescriptor) -> String {
var parts: [String] = []
if let name = descriptor.commonName {
parts.append(name)
}
if let address = descriptor.address {
parts.append(address)
}
if let coord = descriptor.coordinate {
parts.append("\(coord.latitude), \(coord.longitude)")
}
return parts.joined(separator: " -- ")
}
// Bad -- force-unwrapping optional properties
let name = descriptor.commonName! // crashes if nil
let coord = descriptor.coordinate! // crashes if no coordinate representation
Geocoding with Fallback
// Good -- handle empty results and errors
func resolvePlace(_ address: String) async -> PlaceDescriptor? {
do {
let request = MKGeocodingRequest(addressString: address)
let items = try await request.mapItems
guard let item = items.first else {
print("No results for address: \(address)")
return nil
}
return PlaceDescriptor(item: item)
} catch {
print("Geocoding failed: \(error.localizedDescription)")
return nil
}
}
// Bad -- no error handling, no empty check
func resolvePlace(_ address: String) async -> PlaceDescriptor {
let request = MKGeocodingRequest(addressString: address)
let items = try! await request.mapItems // crashes on failure
return PlaceDescriptor(item: items.first!) // crashes if empty
}
Review Checklist
-
import GeoToolboxis present when usingPlaceDescriptor,PlaceRepresentation, orSupportingPlaceRepresentation -
import MapKitis present when usingMKGeocodingRequest,MKReverseGeocodingRequest, orMKMapItem -
import CoreLocationis present when usingCLLocationCoordinate2DorCLLocation -
PlaceDescriptorproperties (coordinate,address,commonName) are checked fornilbefore use - Service identifier keys use defined constants, not raw string literals
-
MKReverseGeocodingRequestreceives aCLLocation, not a rawCLLocationCoordinate2D - Geocoding results are checked for empty arrays before accessing elements
- Geocoding calls use proper
async/awaiterror handling withdo/catch - Multiple representations are provided when both coordinate and address are known
- Supporting representations include service identifiers when cross-service interop is needed
Cross-References
- For MapKit map views and annotations, see MapKit documentation
- For CoreLocation permissions and location updates, see CoreLocation documentation
- For SwiftUI integration with maps, see
Mapview in SwiftUI
References
FAQ
What does the geotoolbox skill do?
GeoToolbox PlaceDescriptor patterns with MapKit integration for location representation, geocoding, and multi-service place identifiers. Use when working with place descriptors, geocoding, or cross-service location data.
How do I install geotoolbox?
Run npx skills add https://github.com/rshankras/claude-code-apple-skills --skill geotoolbox in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/geotoolbox/ (personal) or .claude/skills/geotoolbox/ (project).
Which AI agents can use geotoolbox?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is geotoolbox safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains geotoolbox?
It is published by rshankras in rshankras/claude-code-apple-skills. It has 74 recorded installs.
More from rshankras/claude-code-apple-skills
macos-development
rshankras/claude-code-apple-skills
Comprehensive macOS development guidance including Swift 6+, SwiftUI, SwiftData, architecture patterns, AppKit bridging, and macOS 26 Tahoe APIs. Use for macOS code review, best practices, UI review, or platform-specific features.
ios-development
rshankras/claude-code-apple-skills
Comprehensive iOS development guidance including Swift best practices, SwiftUI patterns, UI/UX review against HIG, and app planning. Use for iOS code review, best practices, accessibility audits, or planning new iOS apps.
design
rshankras/claude-code-apple-skills
Design skills for Apple platform UI — Liquid Glass, animations, game feel (haptics, sound, celebrations), UI prototyping, UX writing, SF Symbols, and typography. Use when implementing design language features, adding juice/feedback, writing interface copy, or choosing type and iconography.
app-store
rshankras/claude-code-apple-skills
App Store optimization and marketing skills for descriptions, screenshots, keywords, review responses, and comprehensive promotional strategy. Use when user needs help with App Store presence, ASO, marketing, or customer communication.
watchos
rshankras/claude-code-apple-skills
watchOS development guidance including SwiftUI for Watch, Watch Connectivity, complications, and watch-specific UI patterns. Use for watchOS code review, best practices, or Watch app development.
product-development
rshankras/claude-code-apple-skills
End-to-end product development for iOS/macOS apps. Covers market research, competitive analysis, PRD generation, architecture specs, UX design, implementation guides, testing, and App Store release. Use for product planning, validation, or generating specification documents.
Popular other skills
hyperframes-cli
heygen-com/hyperframes
The HyperFrames CLI by job - scaffold, check, look at frames, edit the timeline, preview, render locally or in the cloud, publish, project history - plus reading its JSON and recovering from build or render failures.
triage
mattpocock/skills
Move issues and external PRs through a state machine of triage roles, categorise, verify, grill if needed, and write agent-ready briefs.
ask-matt
mattpocock/skills
Ask which skill or flow fits your situation. A router over the skills in this repo.
to-questionnaire
mattpocock/skills
Turn a decision you can't fully answer into a questionnaire for someone else to fill in.
loop-me
mattpocock/skills
Grill me about specs for the workflows I want to build, within this workspace.