一键导入
swift-user-conventions
User's conventions and patterns for native macOS Swift apps. Use when working on a Swift or macOS app project
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
User's conventions and patterns for native macOS Swift apps. Use when working on a Swift or macOS app project
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Teach a personal editor agent the user's own editing taste by reading the diff between an AI-drafted document and the user's hand-edit of it, encoding the lessons as procedures in the agent, and verifying with controlled re-runs. Use whenever the user has edited an AI-written document (README, docs, blog post) and wants their editor agent to learn from it, wants to build a personal editor agent from scratch, or says things like "teach my editor", "learn my house style", "train the humaniser on my edits", "make the editor agent edit more like me", or asks to compare what their editor agent would do against their own edit of the same document.
Generate a GitHub-style README.md for the current project by reading the actual codebase. Use when the user asks to "generate a readme", "write a readme", "document this project", "create a readme", or invokes /readme. Also callable from the github-create skill.
Streamlined workflow for implementing features with ait issue tracking. Handles: reading project context, checking outstanding work, planning new features, creating ait issues, and implementing with proper acceptance criteria checking. Use when starting a new session or beginning work on a feature.
One-stop review after feature work, or for a whole codebase. Runs deterministic checks (section ordering, arch conventions) free of charge, then fresh-eyes reviewer agents. Covers team conventions, test quality, complexity, security, and Livewire/Flux patterns - plus runtime checks (a11y, cold UX probe) when UI changed. Also has a quick mid-session sanity-check mode ("this seem ok?").
Turn a settled feature discussion or plan document into consultant-ready ait issues — an initiative/epic vision document plus implementation specs a fresh agent could pick up cold, tomorrow. Use towards the end of a feature conversation ("let's get this into ait"), or when converting a plan file. Also the knowledge base for the plan-to-ait agent. For driving the ait CLI itself, see the ait skill.
Flesh out a terse ait issue into a detailed plan. Takes a vague "reminder to self" issue and explores the codebase to produce a proper plan document ready for plan-to-ait.
| name | swift-user-conventions |
| description | User's conventions and patterns for native macOS Swift apps. Use when working on a Swift or macOS app project |
| allowed-tools | Read,Write,Edit,Bash,Glob,Grep |
| version | 0.1.0 |
| author | ohnotnow <https://github.com/ohnotnow> |
| license | MIT |
Standards for small native macOS apps — menu-bar utilities, desktop companions, focused tools. These are opinionated defaults, not laws. This skill is young (much younger than its golang sibling): a handful of conventions and a gotcha list earned mostly in one project. When a session teaches a new lesson, add it here rather than leaving it in a transcript.
project.yml is the
source of truth, the generated .xcodeproj is checked in. Regenerate with
xcodegen generate after any structural change, before building.xcodebuild ... -derivedDataPath build build;
run tests with CODE_SIGNING_ALLOWED=NO.SWIFT_STRICT_CONCURRENCY: complete from day one — far cheaper
than retrofitting it later.LSUIElement: true in Info.plist properties../build.sh script
rather than making users run some (probably unfamiliar) xcode/swift commands.network.client).CGWindowListCopyWindowInfo geometry
(owner PID/name, bounds, layer, alpha — not window titles) needs no
permission at all and works sandboxed.UserDefaults, source, test fixtures or logs.UserDefaults, keep that list
truthful when adding features — libraries may write their own defaults (e.g.
KeyboardShortcuts stores the recorded shortcut there).from: a real release tag, and verify the latest with
git ls-remote --tags <url> rather than trusting memory (the model once
confidently guessed "2.x"; reality was 1.10.0).@MainActor on your own static constant — over a
blanket @preconcurrency import.URLProtocol stubs; Keychain
tests use temporary items; the suite never makes live provider calls. Live
API checks are separate opt-in scripts under Tools/.AppRuntime.isRunningUnitTests) so launching the app as a test host spawns
no UI.Drive the real app — a compiling binary and passing tests are necessary, not sufficient. Useful sandboxed, permission-light techniques:
CGWindowListCopyWindowInfo
listing the app's windows by owner name and bounds proves a panel appeared
(window titles would need Screen Recording; bounds don't).UserDefaults before launch to put the app in the
state under test — e.g. KeyboardShortcuts_<name> takes a JSON string
{"carbonKeyCode":N,"carbonModifiers":M}. Read the library's source to
confirm a storage format; never guess it.osascript -e 'tell application "System Events" to key code ...' (the host terminal needs Accessibility; if it's not granted,
degrade gracefully and ask the user to press the key).defaults CLI transparently follows sandboxed apps into their container
(~/Library/Containers/<bundle-id>/...).Mostly from Naiku (https://github.com/ohnotnow/naiku), macOS 26 / Xcode 26.1.1.
Symptom → fix.
NSPanel refuses key status → text fields silently
untypable. Subclass and override var canBecomeKey: Bool { true }.performClose(nil) on a borderless window is a silent no-op —
.closable in the style mask is not enough, AppKit wants an actual close
widget — so windowShouldClose delegate logic never fires. Override
performClose to run the delegate contract yourself, then close().invalidateShadow() does not fix it;
hasShadow = false does. Diagnostic tell: content can't paint outside
window bounds and doesn't change with focus — shadows do both.NSHostingController's default sizingOptions pin the hosting view to
the SwiftUI minimum size, leaving an invisible dead strip inside a larger
window. Set sizingOptions = [] and manage window sizing yourself
(setContentSize + minSize). One print of window.frame vs
window.contentView?.frame settles it..fullScreenAuxiliary does not keep a
.canJoinAllSpaces floating panel out of full-screen Spaces — it
gatecrashes anyway. The only working fix is active self-suppression: watch
Space changes, detect a covering full-screen window via CGWindowList
geometry, and orderOut yourself.NSWorkspace.activeSpaceDidChangeNotification fires mid-transition —
CGWindowList still shows the departing Space's windows at notification time.
Treat the notification as a trigger to start converging, not a reliable read
point: check immediately, re-check ~0.8s later, and poll slowly while in a
suppressed state so recovery never depends on another notification.Timer(target: self) retains its target until invalidated —
a poll timer started only in a rare state is easy to miss in tear-down and
leaks the controller.RegisterEventHotKey (which KeyboardShortcuts
wraps) works inside the App Sandbox with no extra permissions.
NSEvent.addGlobalMonitorForEvents needs Input Monitoring — avoid it.KeyboardShortcuts.Name
constants trip strict concurrency (Name isn't Sendable); isolate them
with @MainActor — both AppKit call sites and SwiftUI body are main-actor
anyway.kCGImageSourceShouldCache / ShouldCacheImmediately do
not make the decode stick: the CGImage stays backed by the compressed PNG
provider and the decoded pixels live in an evictable system cache, so each
redraw can trigger a full decode plus colour-match (NSImage.cacheMode = .never guarantees it). Diagnostic tell: CPU tracks the animation frame
rate, and /usr/bin/sample shows png_read_filter_row_paeth_neon /
CGSImageDataLock under CALayer _display. Fix: at load time, draw the
image once into an owned CGContext (sRGB, premultiplied BGRA,
byteOrder32Little) and keep context.makeImage() — nothing PNG-backed
survives to draw time. Cost is width×height×4 bytes of resident memory.