agentskills.codes

Install

mkdir -p .claude/skills/macos && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/13420" && unzip -o skill.zip -d .claude/skills/macos && rm skill.zip

Installs to .claude/skills/macos

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Implementa funcionalidades específicas de macOS em apps SwiftUI — Scenes (Settings, MenuBarExtra, WindowGroup, Window, UtilityWindow, DocumentGroup), estilos de janela e toolbar, NavigationSplitView, Inspector, Commands, HSplitView, Table, operações de arquivo, drag-drop entre apps, e interop AppKit. Use quando o usuário precisar de qualquer API exclusiva ou com comportamento diferenciado no macOS.
401 charsno explicit “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)

About this skill

Skill: macOS

Você é um especialista em APIs SwiftUI específicas do macOS.
Regra obrigatória: todas as APIs exclusivas de macOS DEVEM estar dentro de #if os(macOS) em projetos multiplataforma.


Identificação do Modo

Se $ARGUMENTS não especificar o modo, pergunte:

"Qual aspecto macOS você quer implementar?

  • scenes — configurar cenas do app (Settings, MenuBarExtra, Window…)
  • window — estilos de toolbar/janela, Inspector, NavigationSplitView, Commands
  • views — HSplitView, Table, arquivos, drag-drop, NSViewRepresentable"

Modo: scenes

Antes de criar

  1. Leia o @main App atual para entender as cenas existentes.
  2. Identifique qual cena adicionar ou ajustar.
  3. Wrap sempre em #if os(macOS) quando o projeto é multiplataforma.

Referência de Cenas

CenaDisponibilidademacOS-only?Uso
WindowGroupmacOS 11.0+NãoMúltiplas janelas, tabs, Window menu automático
WindowmacOS 13.0+NãoJanela singleton; app sai quando fecha (se for única)
UtilityWindowmacOS 15.0+SimPaleta flutuante; recebe FocusedValues da janela ativa
SettingsmacOS 11.0+SimJanela de preferências (Cmd+,)
MenuBarExtramacOS 13.0+SimÍcone/menu persistente na barra de menus
DocumentGroupmacOS 11.0+NãoMenus File automáticos; múltiplos documentos

Settings

#if os(macOS)
Settings {
    TabView {
        Tab("General", systemImage: "gear") { GeneralSettingsView() }
        Tab("Advanced", systemImage: "star") { AdvancedSettingsView() }
    }
    .scenePadding()
    .frame(maxWidth: 350, minHeight: 100)
}
#endif

Abrir programaticamente (macOS 14.0+):

struct OpenSettingsButton: View {
    @Environment(\.openSettings) private var openSettings

    var body: some View {
        Button("Preferências") { openSettings() }
    }
}

SettingsLink (macOS 14.0+):

SettingsLink {
    Label("Preferências", systemImage: "gear")
}

MenuBarExtra

Estilo menu (dropdown):

#if os(macOS)
MenuBarExtra("MyApp", systemImage: "hammer") {
    Button("Ação") { /* ... */ }
    Divider()
    Button("Sair") { NSApplication.shared.terminate(nil) }
}
#endif

Estilo window (painel popover):

#if os(macOS)
MenuBarExtra("Status", systemImage: "chart.bar") {
    DashboardView()
        .frame(width: 240)
}
.menuBarExtraStyle(.window)
#endif

App somente na barra de menus:

  • Use MenuBarExtra como única cena
  • Adicione LSUIElement = YES no Info.plist para ocultar o ícone no Dock
  • O app se encerra automaticamente se o usuário remover o ícone da barra

Visibilidade controlável:

@AppStorage("showMenuBarExtra") private var showMenuBarExtra = true

MenuBarExtra("Status", systemImage: "bolt", isInserted: $showMenuBarExtra) { ... }

WindowGroup (macOS)

@main
struct MyApp: App {
    var body: some Scene {
        // Janela principal (suporta múltiplas instâncias + tabs)
        WindowGroup {
            ContentView()
        }

        // Janela de dados tipados — aberta programaticamente
        WindowGroup("Detalhe", for: Item.ID.self) { $itemID in
            ItemDetailView(itemID: itemID)
        }
    }
}

// Abrir programaticamente
struct OpenButton: View {
    var item: Item
    @Environment(\.openWindow) private var openWindow

    var body: some View {
        Button("Abrir Detalhe") {
            openWindow(value: item.id)
        }
    }
}

Window (singleton)

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup { ContentView() }

        // Janela singleton suplementar
        Window("Connection Doctor", id: "connection-doctor") {
            ConnectionDoctorView()
        }
    }
}

// Abrir — traz ao frente se já aberta
struct OpenDoctorButton: View {
    @Environment(\.openWindow) private var openWindow

    var body: some View {
        Button("Connection Doctor") {
            openWindow(id: "connection-doctor")
        }
    }
}

Prefira WindowGroup para a cena principal. Use Window apenas para janelas suplementares singleton.


UtilityWindow (macOS 15.0+)

Paleta flutuante que recebe FocusedValues da janela principal ativa.

#if os(macOS)
UtilityWindow("Informações", id: "photo-info") {
    PhotoInfoViewer()
}
#endif

// Dentro da UtilityWindow — reflete seleção da janela ativa
struct PhotoInfoViewer: View {
    @FocusedValue(PhotoSelection.self) private var selectedPhotos

    var body: some View {
        if let photos = selectedPhotos {
            Text("\(photos.count) fotos selecionadas")
        } else {
            Text("Sem seleção").foregroundStyle(.secondary)
        }
    }
}

DocumentGroup

DocumentGroup(newDocument: MyDocument()) { config in
    ContentView(document: config.$document)
}
struct MyDocument: FileDocument {
    static var readableContentTypes: [UTType] { [.plainText] }
    var text: String = ""

    init() {}
    init(configuration: ReadConfiguration) throws {
        text = String(data: configuration.file.regularFileContents ?? Data(),
                      encoding: .utf8) ?? ""
    }
    func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
        FileWrapper(regularFileWithContents: Data(text.utf8))
    }
}

Modo: window

Toolbar Styles (macOS-only)

Aplique no nível da Scene:

WindowGroup { ContentView() }
    .windowToolbarStyle(.unified)           // Título + toolbar em uma linha (recomendado)
    .windowToolbarStyle(.unifiedCompact)    // Idem, menor altura vertical
    .windowToolbarStyle(.expanded)          // Título acima da toolbar
    .windowToolbarStyle(.unified(showsTitle: false))  // Sem título

Conteúdo da toolbar na View:

.toolbar {
    ToolbarItem(placement: .automatic) {
        Button(action: addItem) {
            Label("Adicionar", systemImage: "plus")
        }
    }
}
.searchable(text: $searchText, placement: .sidebar)

Window Sizing & Positioning

WindowGroup {
    ContentView()
        .frame(minWidth: 600, minHeight: 400)   // Mínimos no conteúdo
}
.defaultSize(width: 900, height: 600)           // Tamanho inicial
.defaultPosition(.center)                       // Posição inicial
.windowResizability(.contentMinSize)            // Usa minWidth/minHeight do frame

windowResizability opções:

ValorComportamento
.automaticSistema decide
.contentSizeTamanho fixo, sem redimensione
.contentMinSizeRedimensionável com mínimo pelo frame

Posicionamento preciso (macOS 15.0+):

.windowIdealPlacement { context in
    let screen = context.defaultDisplay.visibleArea
    return WindowPlacement(x: screen.midX, y: screen.midY,
                           width: screen.width / 2,
                           height: screen.height)
}

Window Style

// Padrão — barra de título visível
WindowGroup { ContentView() }
    .windowStyle(.titleBar)

// Sem barra de título — janelas imersivas
WindowGroup { ContentView() }
    .windowStyle(.hiddenTitleBar)

NavigationSplitView no macOS

No macOS, as colunas são exibidas lado a lado (nunca sobrepostas). A sidebar recebe fundo translúcido automaticamente.

NavigationSplitView {
    List(items, selection: $selectedID) { item in
        Text(item.name)
    }
    .navigationSplitViewColumnWidth(min: 180, ideal: 220, max: 300)
} detail: {
    DetailView(id: selectedID)
}
.navigationSplitViewStyle(.balanced)

Três colunas:

NavigationSplitView {
    SidebarView()
} content: {
    ContentListView(selection: $selectedItem)
} detail: {
    DetailView(item: selectedItem)
}

Inspector (macOS 14.0+)

Painel lateral direito redimensionável pelo usuário.

struct ContentView: View {
    @State private var showInspector = false

    var body: some View {
        MainContent()
            .inspector(isPresented: $showInspector) {
                InspectorView()
                    .inspectorColumnWidth(min: 200, ideal: 250, max: 400)
            }
            .toolbar {
                ToolbarItem {
                    Button {
                        showInspector.toggle()
                    } label: {
                        Label("Inspetor", systemImage: "info.circle")
                    }
                }
            }
    }
}

Commands & Atalhos de Teclado

// Na Scene
.commands {
    CommandMenu("Ferramentas") {
        Button("Executar Análise") { /* ... */ }
            .keyboardShortcut("r", modifiers: [.command, .shift])
    }
    CommandGroup(after: .newItem) {
        Button("Novo Pelo Template…") { /* ... */ }
    }
}

Atalhos em botões:

Button("Salvar") { save() }
    .keyboardShortcut("s", modifiers: .command)

Button("Excluir") { delete() }
    .keyboardShortcut(.delete, modifiers: .command)

Posicionamentos de CommandGroup: .newItem, .saveItem, .help, .toolbar, .sidebar
Use .replacing(_:) para substituir um grupo do sistema.


Modo: views

HSplitView / VSplitView (macOS-only)

Use para layouts IDE-style onde todos os painéis são pares iguais. Para navegação sidebar → conteúdo, prefira NavigationSplitView.

HSplitView {
    FileTreeView()
        .frame(minWidth: 200)
    CodeEditorView()
        .frame(minWidth: 400)
    PreviewPane()
        .frame(minWidth: 200)
}

VSplitView é idêntico mas divide verticalmente (use minHeight em vez de minWidth).


Table (macOS 12.0+)

struct PeopleTable: View {
    @State private var people: [Person] = Person.samples
    @State private var selection: Set<Person.ID> = []
    @State private var sortOrder = [KeyPathComparator(\Person.name)]

    var body: 

---

*Content truncated.*

Search skills

Search the agent skills registry