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 reading, writing, or watching the macOS clipboard — NSPasteboard types and multiple representations, the changeCount polling pattern, the transient/concealed pasteboard conventions clipboard tools must respect, and the Sequoia paste-privacy alerts.
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Work with NSPasteboard correctly: write rich content with plain-text fallbacks, watch for changes the only way macOS allows (polling changeCount), and — if you're building anything clipboard-manager-shaped — respect the concealed/transient conventions that keep passwords out of your history.
Use this skill when the user says:
NSPasteboardDo not use this skill for iOS (UIPasteboard differs in important ways), or for drag-and-drop UI mechanics (onDrag/Transferable view wiring) beyond the data-type layer.
Write every flavor the receiver might want, richest first.
Read by asking for the best type you can handle.
Never clobber, log, or upload the user's clipboard —
and never store what a password manager marked concealed.
Always clearContents() first — it claims ownership and bumps changeCount. Then declare the richest set of representations you have:
import AppKit
// Simple string
let pb = NSPasteboard.general
pb.clearContents()
pb.setString("hello", forType: .string)
// Rich content with fallbacks: receivers pick the best they support.
// One NSPasteboardItem = one logical thing with multiple flavors.
let item = NSPasteboardItem()
item.setString(htmlString, forType: .html)
item.setString(plainString, forType: .string) // the fallback that
pb.clearContents() // makes TextEdit,
pb.writeObjects([item]) // terminals etc. work
// Files
pb.clearContents()
pb.writeObjects([fileURL as NSURL])
// Multiple files = multiple items, not one item with many flavors
pb.writeObjects(urls as [NSURL])
The classic bug is writing only HTML or only a custom type: paste then silently does nothing in half the apps on the system. Plain .string rides along with almost everything.
Namespace them like a UTI and add them alongside standard flavors:
extension NSPasteboard.PasteboardType {
static let taskItem = NSPasteboard.PasteboardType("com.example.myapp.task")
}
let item = NSPasteboardItem()
item.setData(try JSONEncoder().encode(task), forType: .taskItem) // full fidelity
item.setString(task.title, forType: .string) // world-readable
Your own app pastes with full fidelity; everyone else gets sensible text.
let pb = NSPasteboard.general
// Best-type reading: order = your preference
if let types = pb.types {
if types.contains(.fileURL),
let urls = pb.readObjects(forClasses: [NSURL.self]) as? [URL] {
handle(files: urls)
} else if let s = pb.string(forType: .string) {
handle(text: s)
}
}
// Cheap capability check before enabling a Paste button:
let canPaste = pb.canReadObject(forClasses: [NSURL.self, NSString.self],
options: nil)
Read the pasteboard only on user intent — a paste command, a button, a drop. Reading on timers or at launch is what triggers the privacy alerts below, and it's the behavior they were designed to shame.
There is no notification for pasteboard changes on macOS. The sanctioned pattern is polling changeCount — an integer that increments on every ownership change:
@MainActor
final class PasteboardWatcher {
private var timer: Timer?
private var lastCount = NSPasteboard.general.changeCount
private let onChange: (NSPasteboard) -> Void
init(onChange: @escaping (NSPasteboard) -> Void) {
self.onChange = onChange
}
func start(interval: TimeInterval = 0.5) {
stop()
timer = Timer.scheduledTimer(withTimeInterval: interval,
repeats: true) { [weak self] _ in
guard let self else { return }
let pb = NSPasteboard.general
guard pb.changeCount != self.lastCount else { return }
self.lastCount = pb.changeCount
self.onChange(pb)
}
timer?.tolerance = interval / 2 // let the system coalesce wakeups
}
func stop() {
timer?.invalidate()
timer = nil
}
}
tolerance keeps it off the battery's back.changeCount only — don't read contents to detect change.Any tool that stores clipboard contents must honor the de-facto org.nspasteboard marker types (password managers write them; well-behaved history tools read them):
extension NSPasteboard.PasteboardType {
/// Passwords, secrets — never store, never display
static let concealed = NSPasteboard.PasteboardType("org.nspasteboard.ConcealedType")
/// Ephemeral by intent (e.g. a "paste once" item) — don't keep
static let transient = NSPasteboard.PasteboardType("org.nspasteboard.TransientType")
/// Machine-generated (linters, formatters) — usually skip in history
static let autoGenerated = NSPasteboard.PasteboardType("org.nspasteboard.AutoGeneratedType")
}
func shouldStore(_ pb: NSPasteboard) -> Bool {
guard let types = pb.types else { return false }
return !types.contains(.concealed) && !types.contains(.transient)
}
And the mirror image: if your app copies something secret (a generated token, a recovery code), mark it concealed so other tools skip it:
let item = NSPasteboardItem()
item.setString(secret, forType: .string)
item.setString("", forType: .concealed) // presence is the signal
pb.clearContents()
pb.writeObjects([item])
Since macOS 15.x, reading NSPasteboard.general without user intent can surface a system alert — "AppName pasted from OtherApp" — and a per-app clipboard setting exists under Privacy & Security. Consequences:
canReadObject(forClasses:) / inspect types for UI enablement — checking types is not reading contents."Copy to clipboard" features are fine. But automation that pastes through the clipboard (type-for-the-user tools) must save and restore:
// Snapshot → do your programmatic paste → restore
let saved = pb.pasteboardItems?.map { old -> NSPasteboardItem in
let copy = NSPasteboardItem()
for type in old.types {
if let data = old.data(forType: type) {
copy.setData(data, forType: type)
}
}
return copy
} ?? []
// … write payload, send ⌘V …
pb.clearContents()
pb.writeObjects(saved)
Restore after a short delay (the receiving app must read the payload first). Losing what the user had copied is one of the fastest ways to make them delete your app.
[ ] Writes include a plain .string fallback next to rich/custom flavors
[ ] clearContents() before every write
[ ] Reads happen on user intent only (paste/drop/button), never on timers
[ ] Watching uses changeCount polling with tolerance, and stops when off
[ ] History/storage honors ConcealedType and TransientType
[ ] Own secrets are written with the concealed marker
[ ] Programmatic paste-through saves and restores the user's clipboard
[ ] Nothing from the clipboard is logged, synced, or uploaded
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
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.
日本語の概要は準備中です。原文の説明を表示しています。