Skip to content

Commit 0395c17

Browse files
duyetduyetbot
andauthored
feat(build-macos-apps): add macOS app building skills and commands (#72)
* feat(build-macos-apps): add macOS app building skills and commands New plugin for building, debugging, instrumenting, and implementing macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows. 11 skills (liquid-glass, signing-entitlements, packaging-notarization, test-triage, window-management, telemetry, swiftui-patterns, view-refactor, appkit-interop, build-run-debug, swiftpm-macos) + 3 commands (build-and-run-macos-app, fix-codesign-error, test-macos-app) + agent definition. Claude + Codex manifests included; already registered in the marketplace manifests. Co-Authored-By: duyetbot <duyetbot@users.noreply.github.com> * style(build-macos-apps): satisfy super-linter (MD040, MD013, prettier) - Tag directory-tree fences as text (MD040) - Wrap three guideline lines over 400 chars (MD013) - Collapse codex capabilities array (JSON_PRETTIER) - Apply prettier formatting to 7 SKILL.md files (MARKDOWN_PRETTIER) Co-Authored-By: duyetbot <duyetbot@users.noreply.github.com> --------- Co-authored-by: duyetbot <duyetbot@users.noreply.github.com>
1 parent 13df50e commit 0395c17

30 files changed

Lines changed: 1962 additions & 0 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "build-macos-apps",
3+
"version": "1.0.0",
4+
"description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.",
5+
"author": {
6+
"name": "duyet",
7+
"url": "https://github.com/duyet"
8+
},
9+
"homepage": "https://github.com/duyet/codex-claude-plugins",
10+
"repository": "https://github.com/duyet/codex-claude-plugins",
11+
"license": "MIT"
12+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "build-macos-apps",
3+
"version": "1.0.0",
4+
"description": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance, codesigning, packaging, and telemetry workflows.",
5+
"author": {
6+
"name": "duyet"
7+
},
8+
"skills": "./skills/",
9+
"commands": "./commands/",
10+
"agents": "./agents/",
11+
"interface": {
12+
"displayName": "Build macOS Apps",
13+
"shortDescription": "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance",
14+
"developerName": "duyet",
15+
"category": "development",
16+
"capabilities": ["Skill", "Command", "Agent"],
17+
"links": {
18+
"homepage": "https://github.com/duyet/codex-claude-plugins"
19+
}
20+
}
21+
}

build-macos-apps/README.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Build macOS Apps Plugin
2+
3+
This plugin packages macOS-first development workflows.
4+
5+
It currently includes these skills:
6+
7+
- `build-run-debug`
8+
- `test-triage`
9+
- `signing-entitlements`
10+
- `swiftpm-macos`
11+
- `packaging-notarization`
12+
- `swiftui-patterns`
13+
- `liquid-glass`
14+
- `window-management`
15+
- `appkit-interop`
16+
- `view-refactor`
17+
- `telemetry`
18+
19+
## What It Covers
20+
21+
- discovering local Xcode workspaces, projects, and Swift packages
22+
- building and running macOS apps with shell-first desktop workflows
23+
- creating one project-local `script/build_and_run.sh` entrypoint and wiring `.codex/environments/environment.toml` so the Codex app Run button works
24+
- implementing native macOS SwiftUI scenes, menus, settings, toolbars, and multiwindow flows
25+
- adopting modern macOS Liquid Glass and design-system guidance with standard SwiftUI structures, toolbars, search, controls, and custom glass surfaces
26+
- tailoring SwiftUI windows with title/toolbar styling, material-backed container backgrounds, minimize/restoration behavior, default and ideal placement, borderless window style, and launch behavior
27+
- bridging into AppKit for representables, responder-chain behavior, panels, and other desktop-only needs
28+
- refactoring large macOS view files toward stable scene, selection, and command structure
29+
- adding lightweight `Logger` / `os.Logger` instrumentation for windows, sidebars, menu commands, and menu bar actions
30+
- reading and verifying runtime events with Console, `log stream`, and process logs
31+
- triaging failing unit, integration, and UI-hosted macOS tests
32+
- debugging launch failures, crashes, linker problems, and runtime regressions
33+
- inspecting signing identities, entitlements, hardened runtime, and Gatekeeper issues
34+
- preparing packaging and notarization workflows for distribution
35+
36+
## Plugin Structure
37+
38+
```text
39+
build-macos-apps/
40+
├── .claude-plugin/ # Claude manifest
41+
├── .codex-plugin/ # Codex manifest
42+
├── agents/
43+
│ └── openai.yaml # OpenAI surface metadata
44+
├── assets/ # Icons and SVGs
45+
├── commands/ # Slash commands
46+
│ ├── build-and-run-macos-app.md
47+
│ ├── fix-codesign-error.md
48+
│ └── test-macos-app.md
49+
└── skills/ # Skill payloads
50+
├── build-run-debug/
51+
├── test-triage/
52+
├── signing-entitlements/
53+
├── swiftpm-macos/
54+
├── packaging-notarization/
55+
├── swiftui-patterns/
56+
├── liquid-glass/
57+
├── window-management/
58+
├── appkit-interop/
59+
├── view-refactor/
60+
└── telemetry/
61+
```
62+
63+
## License
64+
65+
MIT
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
interface:
2+
display_name: "Build macOS Apps"
3+
short_description: "Build, debug, instrument, and implement macOS apps with SwiftUI and AppKit guidance"
4+
icon_small: "./assets/build-macos-apps-small.svg"
5+
icon_large: "./assets/app-icon.png"
6+
default_prompt: "Build/refactor native macOS UI, inspect AppKit interop, add telemetry, or debug a macOS app."
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# /build-and-run-macos-app
2+
3+
Create or update the project-local macOS `build_and_run.sh` script, wire the
4+
Codex app Run button, then use that script as the default build/run entrypoint.
5+
6+
## Arguments
7+
8+
- `scheme`: Xcode scheme name (optional)
9+
- `workspace`: path to `.xcworkspace` (optional)
10+
- `project`: path to `.xcodeproj` (optional)
11+
- `product`: SwiftPM executable product name (optional)
12+
- `mode`: `run`, `debug`, `logs`, `telemetry`, or `verify` (optional, default: `run`)
13+
- `app_name`: process/app name to stop before relaunching (optional)
14+
15+
## Workflow
16+
17+
1. Detect whether the repo uses an Xcode workspace, Xcode project, or SwiftPM package.
18+
2. If the workspace is not inside git yet, run `git init` at the project root so Codex app git-backed features unlock.
19+
3. Create or update `script/build_and_run.sh` so it always stops the current app, builds the macOS target, and launches the fresh result.
20+
4. For SwiftPM, keep raw executable launch only for true CLI tools; for AppKit/SwiftUI GUI apps, create a project-local `.app` bundle and launch it with `/usr/bin/open -n`.
21+
5. Support optional script flags for `--debug`, `--logs`, `--telemetry`, and `--verify`.
22+
6. Follow the canonical bootstrap contract in `../skills/build-run-debug/references/run-button-bootstrap.md` for the exact script shape and `.codex/environments/environment.toml` format.
23+
7. Run the script in the requested mode and summarize any build, script, or launch failure.
24+
25+
## Guardrails
26+
27+
- Do not initialize a nested git repo inside an existing parent checkout.
28+
- Do not leave stale `Run` actions pointing at old script paths.
29+
- Keep the no-flag script path simple: kill, build, run.
30+
- Use `--debug`, `--logs`, `--telemetry`, or `--verify` only when the user asks for those modes.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# /fix-codesign-error
2+
3+
Inspect a macOS signing or entitlement failure and explain the minimum fix path.
4+
5+
## Arguments
6+
7+
- `app`: path to `.app` bundle or binary (optional)
8+
- `identity`: signing identity hint (optional)
9+
- `mode`: `inspect` or `repair-plan` (optional, default: `inspect`)
10+
11+
## Workflow
12+
13+
1. Inspect the app bundle, executable, signing info, and entitlements.
14+
2. Determine whether the problem is identity, provisioning, hardened runtime, sandboxing, or trust policy.
15+
3. Summarize the exact failure class in plain language.
16+
4. Provide the minimal repair sequence or validation command.
17+
18+
## Guardrails
19+
20+
- Never invent entitlements; read them from the binary or source files.
21+
- Distinguish local development signing problems from distribution or notarization failures.
22+
- Prefer verifiable commands like `codesign -d`, `spctl`, and `plutil` over guesswork.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# /test-macos-app
2+
3+
Run the smallest meaningful macOS test scope first and explain failures by category.
4+
5+
## Arguments
6+
7+
- `scheme`: Xcode scheme name (optional)
8+
- `target`: test target or product name (optional)
9+
- `filter`: test filter expression (optional)
10+
- `configuration`: `Debug` or `Release` (optional, default: `Debug`)
11+
12+
## Workflow
13+
14+
1. Detect whether the repo uses `xcodebuild test` or `swift test`.
15+
2. Prefer focused test execution when a target or filter is provided.
16+
3. Classify failures as compile, assertion, crash, env/setup, or flake.
17+
4. Summarize the top blocker and the narrowest sensible next step.
18+
19+
## Guardrails
20+
21+
- Avoid rerunning the full suite if a focused rerun is possible.
22+
- Distinguish build failures from actual failing tests.
23+
- Note when host app setup or simulator-only test assumptions leak into a macOS run.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
name: appkit-interop
3+
description: Bridge macOS SwiftUI into AppKit narrowly. Use when implementing representables, reaching NSWindow or panels, handling menus, or using the responder chain.
4+
---
5+
6+
# AppKit Interop
7+
8+
## Quick Start
9+
10+
Use this skill when SwiftUI is close but not quite enough for native macOS behavior.
11+
Keep the bridge as small and explicit as possible. SwiftUI should usually remain
12+
the source of truth, while AppKit handles the imperative edge.
13+
14+
## Choose The Smallest Bridge
15+
16+
- Use pure SwiftUI when the required behavior already exists in scenes, toolbars, commands, inspectors, or standard controls.
17+
- Use `NSViewRepresentable` when you need a specific AppKit view with lightweight lifecycle needs.
18+
- Use `NSViewControllerRepresentable` when you need controller lifecycle, delegation, or presentation coordination.
19+
- Use direct AppKit window or app hooks when you need `NSWindow`, responder-chain, menu validation, panels, or app-level behavior.
20+
21+
## Workflow
22+
23+
1. Name the capability gap precisely.
24+
- Window behavior
25+
- Text system behavior
26+
- Menu validation
27+
- Drag and drop
28+
- File open/save panels
29+
- First responder control
30+
31+
2. Pick the smallest boundary that solves it.
32+
- Avoid porting a whole screen to AppKit when one wrapped control or coordinator would do.
33+
34+
3. Keep ownership explicit.
35+
- SwiftUI owns value state, selection, and observable models.
36+
- AppKit objects stay inside the representable, coordinator, or bridge object.
37+
38+
4. Expose a narrow interface back to SwiftUI.
39+
- Bindings for editable state
40+
- Small callbacks for events
41+
- Focused bridge services only when necessary
42+
43+
5. Validate lifecycle assumptions.
44+
- SwiftUI may recreate representables.
45+
- Coordinators exist to hold delegate and target-action glue, not as a second app architecture.
46+
47+
## References
48+
49+
- `references/representables.md`: choosing between view and view-controller wrappers, plus coordinator patterns.
50+
- `references/window-panels.md`: window access, utility windows, and open/save panels.
51+
- `references/responder-menus.md`: first responder, command routing, and menu validation.
52+
- `references/drag-drop-pasteboard.md`: pasteboard, file URLs, and desktop drag/drop edges.
53+
54+
## Guardrails
55+
56+
- Do not duplicate the source of truth between SwiftUI and AppKit.
57+
- Do not let `Coordinator` become an unstructured dumping ground.
58+
- Do not store long-lived `NSView` or `NSWindow` instances globally without a strong ownership reason.
59+
- Prefer a tiny tested bridge over rewriting the feature in raw AppKit.
60+
- If a pattern can remain entirely in `swiftui-patterns`, keep it there.
61+
62+
## Output Expectations
63+
64+
Provide:
65+
66+
- the exact SwiftUI limitation being crossed
67+
- the smallest recommended bridge type
68+
- the data-flow boundary between SwiftUI and AppKit
69+
- the lifecycle or validation risks to watch
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Drag, Drop, and Pasteboard
2+
3+
## Intent
4+
5+
Use this when desktop drag/drop or pasteboard behavior exceeds what plain SwiftUI modifiers cover comfortably.
6+
7+
## Good fits
8+
9+
- File URL dragging
10+
- Pasteboard interoperability with other macOS apps
11+
- Rich drag previews or AppKit-specific drop validation
12+
- Legacy AppKit views with custom drag types
13+
14+
## Core patterns
15+
16+
- Start with SwiftUI drag/drop APIs when they already cover the use case.
17+
- Drop to AppKit when you need `NSPasteboard`, custom pasteboard types, or older AppKit delegate flows.
18+
- Keep data conversion at the boundary instead of leaking AppKit types through the whole feature.
19+
20+
## Pitfalls
21+
22+
- Do not move your whole list or canvas into AppKit just for one drop target.
23+
- Keep file and pasteboard types explicit and validated.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Representables
2+
3+
## Intent
4+
5+
Use this when wrapping an AppKit control or controller for a SwiftUI macOS app.
6+
7+
## Choose the wrapper type
8+
9+
- Use `NSViewRepresentable` for a view-level bridge such as `NSTextView`, `NSScrollView`, or a custom AppKit control.
10+
- Use `NSViewControllerRepresentable` when you need controller lifecycle, delegate coordination, or AppKit presentation logic.
11+
12+
## Skeleton
13+
14+
```swift
15+
struct LegacyTextView: NSViewRepresentable {
16+
@Binding var text: String
17+
18+
func makeCoordinator() -> Coordinator {
19+
Coordinator(text: $text)
20+
}
21+
22+
func makeNSView(context: Context) -> NSScrollView {
23+
let scrollView = NSScrollView()
24+
let textView = NSTextView()
25+
textView.delegate = context.coordinator
26+
scrollView.documentView = textView
27+
return scrollView
28+
}
29+
30+
func updateNSView(_ nsView: NSScrollView, context: Context) {
31+
guard let textView = nsView.documentView as? NSTextView else { return }
32+
if textView.string != text {
33+
textView.string = text
34+
}
35+
}
36+
37+
final class Coordinator: NSObject, NSTextViewDelegate {
38+
@Binding var text: String
39+
40+
init(text: Binding<String>) {
41+
_text = text
42+
}
43+
44+
func textDidChange(_ notification: Notification) {
45+
guard let textView = notification.object as? NSTextView else { return }
46+
text = textView.string
47+
}
48+
}
49+
}
50+
```
51+
52+
## Pitfalls
53+
54+
- Avoid infinite update loops by only pushing state into AppKit when values actually changed.
55+
- Keep delegates and target-action wiring in the coordinator.
56+
- If the wrapper grows into a full screen, re-evaluate the boundary.

0 commit comments

Comments
 (0)