top of page

Swift for Mac Admins: Building a Small Menu-Bar Tool with AI Help

Writer: MacSmithAI
MacSmithAI
Oct 2
7 min read

Why a menu-bar tool is the right first Swift project

Almost everything we build is invisible. A compliance script runs, a profile lands, a report shows up in a console the end user will never open. The gap that keeps filling the ticket queue isn't enforcement — it's visibility. The user doesn't know whether their Mac is compliant, when it last checked in, or why something is nagging them about an update. So they open a ticket, and somebody on your team spends six minutes reading a console to tell them they're fine.


A menu-bar tool closes that loop. It sits up there next to the clock, it shows four or five facts the user is allowed to see, and it has a button that says "check again." It is also, as native Mac apps go, about the smallest thing you can ship: one SwiftUI scene, no window, no document model, no preferences architecture unless you want one.


That makes it the right place for a bash-native admin to spend a weekend learning Swift — and the right place to find out exactly how much of the work an AI assistant can carry.


What the AI is genuinely good for here

The hard part of Swift for someone who writes shell all day isn't logic. It's ceremony. Property wrappers, result builders, trailing-closure scene syntax, some Scene versus some View, optional unwrapping, the difference between a scene modifier and a view modifier. None of that is conceptually difficult and all of it is slow to look up. It's exactly the category where an assistant that knows the framework saves you real hours.


Xcode now has that assistant built in. Apple's own announcement for Xcode 26.3 describes agents that can "search documentation, explore file structures, update project settings, and verify their work visually by capturing Xcode Previews and iterating through builds and fixes," with those capabilities exposed over the Model Context Protocol so you can bring your own compatible agent. For a project this size, the build-and-fix loop is the feature that matters: you are going to get the scene syntax wrong, and you want something that reads the compiler error rather than you.


Which assistant to point at it is a separate question, and one this blog has already worked through in Claude vs. Codex vs. Native Xcode Intelligence. The short version for this project: it's Apple-framework work, so lean toward the assistant that writes idiomatic SwiftUI.


Three things an assistant will get wrong

The availability line. Apple's documentation for MenuBarExtra carries exactly one platform entry: macOS: 13.0.0 -. It is a Ventura-and-later API. That is almost certainly fine for a fleet that's already on macOS 26 or 27, but it is the kind of constraint a generated snippet will never mention, and it is the difference between a project that builds and a deployment target you have to go change.


The presentation style. By default a menu bar extra renders as a menu — a vertical stack of buttons, like a context menu. For anything data-rich, Apple's own guidance is to use the window style, which "displays a popover-like window from the menu bar icon that contains standard controls." The modifier is .menuBarExtraStyle(.window), and an assistant asked for "a menu bar app" will usually hand you the default menu and leave you wondering why your layout collapses.


The Dock icon. A menu-bar-only utility should not appear in the Dock or the app switcher. Apple's instruction is to "set the LSUIElement flag in your app's Information Property List file to true." Worth knowing alongside it: Apple also documents that "an app that only shows in the menu bar will be automatically terminated if the user removes the extra from the menu bar" — so the user has a quit path whether you give them one or not.


The whole app

That's genuinely it. The scene is the app:


import SwiftUI

@main
struct FleetStatusApp: App {
    var body: some Scene {
        MenuBarExtra("Fleet Status", systemImage: "checkmark.seal") {
            StatusPanel()
        }
        .menuBarExtraStyle(.window)
    }
}

struct StatusPanel: View {
    @StateObject private var model = StatusModel()

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            Text(model.headline)
                .font(.headline)
            ForEach(model.rows, id: \.label) { row in
                HStack {
                    Text(row.label)
                    Spacer()
                    Text(row.value)
                        .foregroundStyle(.secondary)
                }
            }
            Divider()
            Button("Check Again") {
                model.reload()
            }
            Button("Quit") {
                NSApplication.shared.terminate(nil)
            }
            .keyboardShortcut("q")
        }
        .padding(12)
        .frame(width: 280)
    }
}

The one architectural decision worth making yourself, rather than letting an assistant make it: don't have the app shell out to collect its own facts. You already have scripts that gather compliance state, and they already run on a schedule with the privileges they need. Have them write their results to a file, and have the menu-bar app read that file. The app stays unprivileged, you keep one source of truth, and when the check logic changes you edit bash instead of rebuilding a Swift binary.


The part no assistant can do for you

Here is where the AI help stops being the bottleneck and your Apple Developer account becomes one. Apple's requirements for the notary service are specific and non-negotiable: code-sign every executable you distribute, use a Developer ID certificate ("Don't use a Mac Distribution, ad hoc, Apple Developer, or local development certificate"), enable the Hardened Runtime, include a secure timestamp, and don't ship the com.apple.security.get-task-allow entitlement set to true. Apple is also explicit that since macOS 10.15, "all software built after June 1, 2019, and distributed with Developer ID must be notarized."


The command-line path is short. Store credentials once, submit, wait, staple:


# confirm which signing identities you actually have
security find-identity -p basic -v

# one-time: save an App Store Connect credential to the keychain
xcrun notarytool store-credentials --apple-id "name@example.com" --team-id "ABCD123456"

# build a signed installer package
pkgbuild --root ./payload --identifier "com.example.fleetstatus" \
  --version "1.0" --install-location "/" \
  --sign "Developer ID Installer: Name (ABCD123456)" FleetStatus-1.0.pkg

# notarize, then attach the ticket
xcrun notarytool submit FleetStatus-1.0.pkg --keychain-profile "notary-profile" --wait
xcrun stapler staple FleetStatus-1.0.pkg
spctl --assess -vv --type install FleetStatus-1.0.pkg

None of that is something to generate and trust. It touches certificates, a team identifier, and a keychain profile that are specific to your organization, and the failure mode of a plausible-looking wrong answer is a package that installs on your machine and fails on 10,000 others.


Getting it onto the fleet

This is where a Mac admin's version of the project diverges from a developer's, and where the Intune constraints are worth reading before you build rather than after. For a macOS line-of-business app, Microsoft's documentation is blunt: .pkg files only, up to 2 GB, and the package must be "a component package or a package containing multiple packages," must not "contain a bundle or disk image or .app file," must be "signed using a 'Developer ID Installer' certificate," and must contain a payload — because "packages without a payload attempt to reinstall as long as the app remains assigned to the group." There's also a detail that bites: macOS LOB apps need a logo, or they don't show in the apps section. You add it under Apps > All Apps > Create, pick the macOS platform, then Line-of-business app.


The second fleet-scale piece is launch at login. Since macOS 13, login items and background tasks are managed through Apple's Service Management framework, and there's a matching management payload so you can pre-approve your own tool rather than asking every user to go turn it on. Apple documents five rule types in that payload — application bundle identifier, bundle identifier prefix, developer team identifier, service label, and service label prefix — and notes that "when an item matches a rule, the item is automatically approved." Users can see the result in System Settings > General > Login Items and can snooze the notification for up to a week, but they can't prevent a managed item from installing. Pre-approving by team identifier is the cleanest option if you're going to ship more than one small tool.



Hand it to the AI?

Why

SwiftUI scene and view scaffolding

Yes

Boilerplate with one right answer - a wrong guess fails to compile immediately

Parsing the output your scripts already produce

Yes

String and JSON handling is where the syntax gap costs an admin the most time

Info.plist keys and the deployment target

Draft, then verify

Apple's docs carry the availability line - check it rather than trusting the suggestion

Code signing and notarization

No

Certificates, the hardened runtime and your developer account are account state, not code

The pkg Intune ingests

Only the pkgbuild line

Intune rejects a package for reasons a build log will not tell you

Anything that reads user data

No

A privacy-sensitive read belongs in a design review before it belongs in an editor


The practical takeaway

Build it, and use the AI for the Swift and nothing else. Scope the tool to read-only display of facts your existing scripts already produce, let an assistant write the SwiftUI scene and the parsing, and target macOS 13 or later so MenuBarExtra is available to you. Then draw a hard line at the signing step: get a Developer ID Application certificate and a Developer ID Installer certificate, sign and notarize by hand the first few times until the commands are boring, and wrap them in a script only once you understand what each flag is doing.


The reason this is worth a weekend isn't the tool. It's that "I can ship a signed, notarized, MDM-deployable native Mac app" moves a whole category of small problems out of the ticket queue and into something you can build on a Friday — and the syntax gap that used to make that a three-month project is, for a tool this size, genuinely closed now.



Comments


bottom of page