Use when creating a new project folder, starter pack, app scaffold, or agent-ready workspace — AGENTS.md, README, TASKS, DECISIONS, PROMPTS, an idempotent bootstrap script, and starter-pack modes.
日本語の概要は準備中です。原文の説明を表示しています。
Use when adding or reviewing macOS user notifications — UNUserNotificationCenter permission flow, categories and action buttons, click routing through the delegate, foreground presentation, and rules that keep notifications from becoming spam.
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Notify only when the user benefits from being pulled back — task finished, task failed, something needs their decision — and make every notification click land on the exact screen that resolves it.
Use this skill when the user says:
UNUserNotificationCenter / UserNotificationsDo not use this skill for push/APNs server setup, iOS-specific notification UI, or in-window status banners (those are in-app feedback — see apple-hig-feedback-status).
Notify only when being pulled back saves the user something.
Every notification answers: what happened, and what happens
when I click it.
Worth a notification (the app is likely in the background):
Completed long task finished → click opens the result
Failed long task failed → click opens the error + retry
Blocked waiting on input/approval → click opens the decision
Needs review output ready to check → click opens the review view
Reminder user-scheduled → click opens the item
Not worth one:
If the app fires more than a handful of notifications an hour, the model is wrong — batch them (one summary notification) or drop the low-value ones.
Request at the moment of need, with context, never at first launch:
import UserNotifications
enum Notifier {
// Call right after the user does the thing that will later notify —
// e.g. starts their first long-running task.
static func requestPermission() async -> Bool {
let center = UNUserNotificationCenter.current()
do {
return try await center.requestAuthorization(options: [.alert, .sound, .badge])
} catch {
return false
}
}
// Never assume — settings can change behind the app's back.
static func isAuthorized() async -> Bool {
let settings = await UNUserNotificationCenter.current().notificationSettings()
return settings.authorizationStatus == .authorized
|| settings.authorizationStatus == .provisional
}
}
Rules:
requestAuthorization won't re-prompt — your only path is Settings, so keep a "notifications are off" state in your own Settings pane with a deep link:// Opens System Settings > Notifications
NSWorkspace.shared.open(
URL(string: "x-apple.systempreferences:com.apple.Notifications-Settings.extension")!)
.provisional for low-stakes apps: notifications deliver quietly to Notification Center without any prompt, and the user promotes or demotes them from there.Define categories once at launch; they give notifications buttons and give clicks a routable identity:
enum TaskNotification {
static let category = "task.finished"
static let retryAction = "task.retry"
static func registerCategories() {
let retry = UNNotificationAction(identifier: retryAction,
title: "Retry",
options: [])
let category = UNNotificationCategory(identifier: category,
actions: [retry],
intentIdentifiers: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
}
static func post(taskID: String, title: String, body: String) async {
guard await Notifier.isAuthorized() else { return }
let content = UNMutableNotificationContent()
content.title = title // "Export failed"
content.body = body // "3 of 120 items didn't convert."
content.sound = .default
content.categoryIdentifier = category
content.userInfo = ["taskID": taskID] // routing payload
content.threadIdentifier = "tasks" // groups related ones
let request = UNNotificationRequest(identifier: taskID, // same ID = replaces
content: content,
trigger: nil) // deliver now
try? await UNUserNotificationCenter.current().add(request)
}
}
Details that matter:
blocked → completed.threadIdentifier keeps a burst of task notifications stacked instead of carpeting the screen.Without a delegate, clicks just activate the app and notifications hide while the app is frontmost. Set it early (before any notification can arrive):
import AppKit
import UserNotifications
final class AppDelegate: NSObject, NSApplicationDelegate,
UNUserNotificationCenterDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
UNUserNotificationCenter.current().delegate = self
TaskNotification.registerCategories()
}
// Route the click to the exact screen that resolves it.
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse) async {
let info = response.notification.request.content.userInfo
guard let taskID = info["taskID"] as? String else { return }
switch response.actionIdentifier {
case TaskNotification.retryAction:
await TaskStore.shared.retry(taskID)
default: // plain click
NSApp.activate(ignoringOtherApps: true)
Router.shared.open(.taskDetail(taskID))
}
}
// Decide what happens if the app is frontmost when one arrives.
// Default: show nothing. Menu bar / background-style apps usually
// still want the banner; window apps showing that screen don't.
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification) async
-> UNNotificationPresentationOptions {
[.banner, .sound]
}
}
// SwiftUI wiring:
@main
struct MyApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene { /* … */ }
}
Also clean up after yourself — when the user opens the screen a notification points at, remove it from Notification Center:
UNUserNotificationCenter.current()
.removeDeliveredNotifications(withIdentifiers: [taskID])
Give users per-type control inside the app, on top of the system switch:
Notifications
Notify me when:
[x] A run completes
[x] A run fails or is blocked
[ ] A daily summary is ready
Notifications are disabled in System Settings. Open Settings… (only when denied)
Check the per-type toggles in your own post() path — isAuthorized() handles the system layer, these handle taste.
[ ] Permission requested at the moment of need, with a pre-explanation
[ ] Denied state visible in app Settings with a System Settings deep link
[ ] Delegate set in applicationDidFinishLaunching, categories registered
[ ] Every notification click opens the exact relevant screen
[ ] Failure notifications carry a recovery action (Retry / Show error)
[ ] Identifiers reused so state changes replace, not stack
[ ] threadIdentifier groups bursts; no notification-per-tick spam
[ ] Delivered notifications removed once the user has seen the thing
[ ] Per-type toggles in app Settings
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Use when creating a new project folder, starter pack, app scaffold, or agent-ready workspace — AGENTS.md, README, TASKS, DECISIONS, PROMPTS, an idempotent bootstrap script, and starter-pack modes.
日本語の概要は準備中です。原文の説明を表示しています。
Use when designing or implementing states for AI agent tasks, background jobs, local model runs, queues, and notifications — one shared set of states, only legal transitions, and a recovery path out of every failure.
日本語の概要は準備中です。原文の説明を表示しています。
Use when exposing app features to App Intents, Shortcuts, Siri, Spotlight, widgets, controls, or system actions — small safe AppIntents, AppShortcutsProvider, AppEnum/AppEntity, parameters, and open-vs-background behavior.
日本語の概要は準備中です。原文の説明を表示しています。
Use when designing, reviewing, or implementing a command-palette / ⌘K layer for an Apple-platform app — keyboard-first global search, ranked and grouped results, native floating panel, and protected destructive commands.
日本語の概要は準備中です。原文の説明を表示しています。
Use when designing or implementing empty, first-run, no-result, offline, error, or waiting states in Apple-platform apps — every empty state explains what is missing, why it matters, and what to do next.
日本語の概要は準備中です。原文の説明を表示しています。
Use when designing or implementing feedback, status, progress, alerts, errors, success states, and live activity indicators in Apple-platform apps — inline status, banners, alerts, notifications, and loading states.
日本語の概要は準備中です。原文の説明を表示しています。