.claude/skills/tooling/macos-scenes/SKILL.md
macOS SwiftUI scene types, window management, and multi-window patterns. Use when building app structure, adding windows, or managing window lifecycle.
npx skillsauth add brdohman/agile-maestro macos-scenesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Most apps start here. Supports multiple windows, tabbed windows, Cmd+N for new.
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.defaultSize(width: 900, height: 600)
}
}
Data-presenting windows (macOS 13+):
WindowGroup(for: Message.ID.self) { $messageID in
MessageDetail(messageID: messageID)
} defaultValue: {
model.makeNewMessage().id
}
Value type must conform to Hashable and Codable (for state restoration).
One instance only. Use for About, Connection Doctor, auxiliary panels.
Window("About MyApp", id: "about") {
AboutView()
}
.windowResizability(.contentSize)
Calling openWindow(id:) again brings existing to front. If Window is the only scene, app quits on close.
Floating tool palettes and inspectors. Stays visible when switching main windows. Hides when app deactivates.
UtilityWindow("Inspector", id: "inspector") {
InspectorView()
}
Always wrap in #if os(macOS). Automatically adds "Settings..." (Cmd+,) to app menu.
#if os(macOS)
Settings {
SettingsView()
}
#endif
Persistent icon in system menu bar.
MenuBarExtra("Status", systemImage: "chart.bar") {
StatusMenu()
}
.menuBarExtraStyle(.window) // .menu for pull-down, .window for popover
Set LSUIElement = true in Info.plist for menu-bar-only apps (no Dock icon).
File-based apps. Adds New/Open/Save/Save As/Revert to File menu automatically.
DocumentGroup(newDocument: MyDocument()) { file in
ContentView(document: file.$document)
}
Requires UTExportedTypeDeclarations in Info.plist.
@Environment(\.openWindow) private var openWindow
@Environment(\.dismissWindow) private var dismissWindow
@Environment(\.openSettings) private var openSettings // macOS 14+
// Open by ID
openWindow(id: "detail-viewer")
// Open with value (matches WindowGroup(for:))
openWindow(value: item.id)
// Open settings programmatically
openSettings()
WindowGroup {
ContentView()
.frame(minWidth: 600, maxWidth: .infinity, minHeight: 400, maxHeight: .infinity)
}
.defaultSize(width: 900, height: 600)
.defaultPosition(.center)
.windowResizability(.contentMinSize) // enforces min from .frame()
| Resizability | Behavior |
|---|---|
| .automatic | Default. Settings uses contentSize, others use contentMinSize |
| .contentSize | Min AND max from content's .frame() |
| .contentMinSize | Only min from content's .frame(), no max |
// Per-scene storage (survives app restart)
@SceneStorage("selectedTab") private var selectedTab = "home"
// Disable restoration for specific windows
Window("Ephemeral", id: "temp") {
TempView()
}
.restorationBehavior(.disabled) // macOS 15+
WindowGroup(for:) automatically persists and restores the bound value.
Standard app (main + preferences):
var body: some Scene {
WindowGroup { ContentView() }
#if os(macOS)
Settings { SettingsView() }
#endif
}
App with auxiliary window:
var body: some Scene {
WindowGroup { MainView() }
Window("Activity Log", id: "activity-log") { ActivityLogView() }
#if os(macOS)
Settings { SettingsView() }
#endif
}
Menu bar utility:
var body: some Scene {
MenuBarExtra("Utility", systemImage: "hammer") { UtilityMenu() }
.menuBarExtraStyle(.window)
}
Window as primary scene quits app on close. Use WindowGroup unless you want this.WindowGroup(for:) passes nil on File > New Window. Always handle nil or provide defaultValue..windowResizability(.contentSize) requires .frame() on content view or it has no size info..scenePadding() is required inside Settings for proper insets.#if os(macOS) around Settings scene.testing
XCTest patterns for macOS Swift apps. Unit tests, async tests, Core Data tests, mock patterns, and assertion reference. Use when writing or reviewing tests.
tools
How to transition workflow state between review stages. Rules for setting review_stage and review_result fields on Stories and Epics.
documentation
Comment structure and rules for task workflow updates. Use when adding any comment to a task during implementation, review, or fix cycles.
testing
Validate task/story/epic/bug/techdebt metadata against schema v2.0. Run after TaskCreate or TaskUpdate to verify compliance. Returns pass/fail with actionable details.