MCPInstall

swift-macos

Build macOS applications - AppKit, windows, menus, system integration, distribution

Installs
48
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/pluginagentmarketplace/custom-plugin-swift --skill swift-macos
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads swift-macos automatically when relevant.

  3. 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.

Swift macOS Skill

Native macOS application development with AppKit, system integration, and distribution.

Prerequisites

  • Xcode 15+ on macOS Sonoma+
  • Apple Developer account (for distribution)
  • Understanding of AppKit fundamentals

Parameters

parameters:
  distribution_method:
    type: string
    enum: [app_store, developer_id, none]
    default: developer_id
  sandbox_enabled:
    type: boolean
    default: true
  min_macos_version:
    type: string
    default: "13.0"
  app_type:
    type: string
    enum: [document_based, single_window, menu_bar, agent]
    default: single_window

Topics Covered

AppKit Components

ComponentPurpose
NSWindowWindow management
NSViewControllerView controller
NSViewBase view class
NSMenuMenu bar and context menus
NSStatusItemMenu bar icon
NSAlertDialog boxes

Window Types

TypeUse Case
NSWindowStandard window
NSPanelUtility/floating window
NSPopoverAttached popover
NSSavePanel/NSOpenPanelFile dialogs

Distribution Methods

MethodRequirements
Mac App StoreSandbox, App Review
Developer IDNotarization
DirectNone (Gatekeeper blocks)

Code Examples

Menu Bar Application

import AppKit
import SwiftUI

@main
struct MenuBarApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        Settings {
            SettingsView()
        }
    }
}

final class AppDelegate: NSObject, NSApplicationDelegate {
    private var statusItem: NSStatusItem!
    private var popover: NSPopover!

    func applicationDidFinishLaunching(_ notification: Notification) {
        setupStatusItem()
        setupPopover()

        // Hide dock icon for menu bar only app
        NSApp.setActivationPolicy(.accessory)
    }

    private func setupStatusItem() {
        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)

        if let button = statusItem.button {
            button.image = NSImage(systemSymbolName: "star.fill", accessibilityDescription: "App")
            button.action = #selector(togglePopover)
        }
    }

    private func setupPopover() {
        popover = NSPopover()
        popover.contentSize = NSSize(width: 300, height: 400)
        popover.behavior = .transient
        popover.contentViewController = NSHostingController(rootView: PopoverView())
    }

    @objc private func togglePopover() {
        guard let button = statusItem.button else { return }

        if popover.isShown {
            popover.performClose(nil)
        } else {
            popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
            popover.contentViewController?.view.window?.makeKey()
        }
    }
}

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

    var body: some View {
        VStack(spacing: 16) {
            Text("Menu Bar App")
                .font(.headline)

            Button("Settings") {
                openSettings()
            }

            Button("Quit") {
                NSApp.terminate(nil)
            }
        }
        .padding()
    }
}

NSDocument-Based App

import AppKit

final class Document: NSDocument {
    var content: String = ""

    override class var autosavesInPlace: Bool { true }

    override func makeWindowControllers() {
        let contentVC = ContentViewController(document: self)
        let window = NSWindow(contentViewController: contentVC)
        window.setContentSize(NSSize(width: 800, height: 600))

        let windowController = NSWindowController(window: window)
        addWindowController(windowController)
    }

    override func data(ofType typeName: String) throws -> Data {
        guard let data = content.data(using: .utf8) else {
            throw NSError(domain: NSOSStatusErrorDomain, code: writErr)
        }
        return data
    }

    override func read(from data: Data, ofType typeName: String) throws {
        guard let content = String(data: data, encoding: .utf8) else {
            throw NSError(domain: NSOSStatusErrorDomain, code: readErr)
        }
        self.content = content
    }
}

final class ContentViewController: NSViewController {
    private let document: Document

    init(document: Document) {
        self.document = document
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) not implemented")
    }

    override func loadView() {
        let scrollView = NSScrollView()
        let textView = NSTextView()

        textView.isEditable = true
        textView.isRichText = false
        textView.font = .monospacedSystemFont(ofSize: 13, weight: .regular)
        textView.string = document.content

        scrollView.documentView = textView
        scrollView.hasVerticalScroller = true

        view = scrollView
    }
}

Sandboxing with Security-Scoped Bookmarks

final class SandboxedFileAccess {
    private static let bookmarksKey = "securityScopedBookmarks"

    static func requestAccess(to url: URL) throws -> URL {
        let bookmark = try url.bookmarkData(
            options: .withSecurityScope,
            includingResourceValuesForKeys: nil,
            relativeTo: nil
        )

        var bookmarks = UserDefaults.standard.dictionary(forKey: bookmarksKey) as? [String: Data] ?? [:]
        bookmarks[url.path] = bookmark
        UserDefaults.standard.set(bookmarks, forKey: bookmarksKey)

        return url
    }

    static func accessBookmarkedURL(_ path: String) throws -> URL {
        guard let bookmarks = UserDefaults.standard.dictionary(forKey: bookmarksKey) as? [String: Data],
              let bookmarkData = bookmarks[path] else {
            throw SandboxError.noBookmark
        }

        var isStale = false
        let url = try URL(
            resolvingBookmarkData: bookmarkData,
            options: .withSecurityScope,
            relativeTo: nil,
            bookmarkDataIsStale: &isStale
        )

        if isStale {
            _ = try requestAccess(to: url)
        }

        return url
    }

    static func withAccess<T>(to url: URL, perform: (URL) throws -> T) throws -> T {
        guard url.startAccessingSecurityScopedResource() else {
            throw SandboxError.accessDenied
        }
        defer { url.stopAccessingSecurityScopedResource() }
        return try perform(url)
    }
}

enum SandboxError: Error {
    case noBookmark
    case accessDenied
}

Notarization Script

#!/bin/bash
set -e

APP_PATH="$1"
DEVELOPER_ID="Developer ID Application: Your Name (TEAMID)"
KEYCHAIN_PROFILE="notary-profile"

echo "Signing..."
codesign --force --options runtime --sign "$DEVELOPER_ID" \
    --deep --strict "$APP_PATH"

echo "Creating ZIP..."
ditto -c -k --keepParent "$APP_PATH" "app.zip"

echo "Submitting for notarization..."
xcrun notarytool submit "app.zip" \
    --keychain-profile "$KEYCHAIN_PROFILE" \
    --wait

echo "Stapling..."
xcrun stapler staple "$APP_PATH"

echo "Verifying..."
spctl --assess --type execute --verbose=2 "$APP_PATH"

echo "Done!"
rm "app.zip"

Troubleshooting

Common Issues

IssueCauseSolution
"App is damaged"Not notarizedNotarize before distribution
Sandbox violationMissing entitlementAdd required entitlement
Window not appearingWrong activation policyCheck NSApp.activationPolicy
Menu not respondingMissing target/actionVerify menu item connections
Sparkle updates failCode signing issueAdd exception entitlement

Debug Tips

# Check code signing
codesign -dv --verbose=4 App.app

# Check entitlements
codesign -d --entitlements :- App.app

# Check notarization
spctl --assess --type execute App.app

# View sandbox violations
log show --predicate 'subsystem == "com.apple.sandbox"' --last 1h

Validation Rules

validation:
  - rule: hardened_runtime
    severity: error
    check: Enable hardened runtime for notarization
  - rule: sandbox_entitlements
    severity: warning
    check: Only request necessary sandbox entitlements
  - rule: code_signing
    severity: error
    check: Sign with Developer ID for distribution

Usage

Skill("swift-macos")

Related Skills

  • swift-swiftui - SwiftUI on macOS
  • swift-architecture - App architecture
  • swift-testing - Testing macOS apps

FAQ

What does the swift-macos skill do?

Build macOS applications - AppKit, windows, menus, system integration, distribution

How do I install swift-macos?

Run npx skills add https://github.com/pluginagentmarketplace/custom-plugin-swift --skill swift-macos 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/swift-macos/ (personal) or .claude/skills/swift-macos/ (project).

Which AI agents can use swift-macos?

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 swift-macos 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 swift-macos?

It is published by pluginagentmarketplace in pluginagentmarketplace/custom-plugin-swift. It has 48 recorded installs.

More from pluginagentmarketplace/custom-plugin-swift

View all →

swift-uikit

pluginagentmarketplace/custom-plugin-swift

Open the skill to read its SKILL.md instructions.

Mobile61 installs

Popular mobile skills

View category →

design-mobile-apps

designed-by-ai/skills

Design mobile app screens with Sleek, edit Sleek projects, and implement their designs in React Native or HTML.

Mobile1.1M installs

ios-design

uizze.sh

Design and review iOS UI/UX for iPhone apps in SwiftUI, UIKit, or React Native. Use for mobile app design, screen redesigns, navigation flows, typography, forms, keyboard and safe-area layout, and accessibility checks. Apply Apple Human Interface Guidelines and consult real product references through the optional Uizze connection.

Mobile416.5K installs

vercel-react-native-skills

vercel-labs/agent-skills

React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.

OfficialMobile256.7K installs

animate-expo

emilkowalski/skills

Build animations in React Native and Expo, making the decisions in the order that determines whether they feel right — should it animate, which thread it runs on, which properties, spring or timing, how the gesture hands off, how it degrades. Writes the implementation with Reanimated, Gesture Handler, Expo Router and expo-haptics. Use when animating anything in an Expo app, adding gestures, sheets, screen transitions, press feedback or haptics, or fixing motion that stutters on device. For web animation use animate.

Mobile140.1K installs

xcode-project-setup

firebase/agent-skills

Safely modifies Xcode projects (.pbxproj) to add Swift Packages and link files. Use this skill whenever an iOS project needs dependencies installed (e.g. Firebase, Alamofire).

OfficialMobile131.2K installs

firebase-remote-config-basics

firebase/agent-skills

Manages Firebase Remote Config templates, feature flags, loading strategies, and SDKs (Android, iOS). Use when downloading/deploying remoteconfig JSON templates, managing version history/feature flags, setting in-app defaults, fetchAndActivate(), real-time listeners, or SDK setup. Don't use for Firebase Hosting, Auth, Firestore, Data Connect, Crashlytics, or App Hosting.

OfficialMobile121.7K installs