apple: add TipKit workflow guidance#119
Conversation
📝 WalkthroughWalkthroughAdds a new ChangesTipKit workflow
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Developer
participant TipKitWorkflow
participant CustomizationCLI
participant RepositoryTests
Developer->>TipKitWorkflow: Request TipKit implementation or troubleshooting guidance
TipKitWorkflow->>CustomizationCLI: Inspect or apply documented customization
CustomizationCLI-->>TipKitWorkflow: Return effective configuration
TipKitWorkflow-->>Developer: Provide platform-specific workflow and testing guidance
RepositoryTests->>TipKitWorkflow: Validate documentation and metadata
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (1)
plugins/apple-dev-skills/tests/test_tipkit_workflow.py (1)
18-19: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse
subTestin loop-based assertions for faster failure diagnosis.The loops at lines 18–19 and 27–28 concatenate two files and check multiple terms, but without
subTest, a failure reports only the first missing term without identifying which one. Wrapping each iteration insubTestpreserves the one-assert-per-failure clarity used in the other test files in this repo.♻️ Proposed refactor for lines 18–19
- for term in ("Tips.configure", "TipView", "popoverTip", "TipUIView", "TipUIPopoverViewController", "TipNSView", "TipNSPopover"): - self.assertIn(term, skill + presentation) + for term in ("Tips.configure", "TipView", "popoverTip", "TipUIView", "TipUIPopoverViewController", "TipNSView", "TipNSPopover"): + with self.subTest(term=term): + self.assertIn(term, skill + presentation)Also applies to: 27-28
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plugins/apple-dev-skills/tests/test_tipkit_workflow.py` around lines 18 - 19, Update the loop-based assertions in the affected tests to wrap each term check in a self.subTest context, including both loops around the assertions over skill + presentation. Preserve the existing terms and assertIn behavior while ensuring failures identify the specific term that is missing.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@plugins/apple-dev-skills/README.md`:
- Line 153: Reconcile the skill inventory centered on the README’s
tipkit-workflow entry so the documented list matches the canonical 33-skill
count required by validate_repo_docs.sh and test_tipkit_workflow.py. Prefer
removing or correcting the extra inventory entries to restore exactly 33, unless
intentionally updating every registration and validation contract consistently.
In
`@plugins/apple-dev-skills/skills/tipkit-workflow/scripts/customization_config.py`:
- Around line 113-121: Update dump_yaml to serialize an empty config["settings"]
mapping as “settings: {}” rather than emitting a bare “settings:” line. Preserve
the existing indented key serialization for non-empty settings so
validate_config() can reload both cases as mappings.
- Around line 38-45: Update encode_scalar to serialize supported scalar types
without converting them to quoted strings, especially preserving float values
through apply and reload. Retain the existing boolean, integer, None, and string
handling, and align the additional scalar cases with the types accepted by
validate_config().
- Around line 173-175: Update the configuration write flow around durable_path()
to write dump_yaml(updated) to a temporary file in target.parent, then
atomically replace target using os.replace(). Preserve UTF-8 encoding and ensure
the temporary file is cleaned up if replacement fails.
- Around line 71-73: Update the top-level and applicable nested key validation
around ALLOWED_TOP_LEVEL to detect non-string mapping keys before sorting
unknown keys or passing keys to regex validation. Route these cases through fail
with the CLI’s normal validation error, while preserving existing handling for
valid string keys.
In `@plugins/apple-dev-skills/skills/tipkit-workflow/SKILL.md`:
- Line 3: Update the TipKit skill description to remove the term “onboarding”
and any onboarding-oriented guidance, while preserving its contextual
feature-discovery scope and all existing TipKit symbols and workflows.
---
Nitpick comments:
In `@plugins/apple-dev-skills/tests/test_tipkit_workflow.py`:
- Around line 18-19: Update the loop-based assertions in the affected tests to
wrap each term check in a self.subTest context, including both loops around the
assertions over skill + presentation. Preserve the existing terms and assertIn
behavior while ensuring failures identify the specific term that is missing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 2670db12-ac79-4510-8d82-ca18bf740ea5
📒 Files selected for processing (17)
plugins/apple-dev-skills/.codex-plugin/plugin.jsonplugins/apple-dev-skills/.github/scripts/validate_repo_docs.shplugins/apple-dev-skills/README.mdplugins/apple-dev-skills/ROADMAP.mdplugins/apple-dev-skills/docs/maintainers/customization-consolidation-review.mdplugins/apple-dev-skills/skills/tipkit-workflow/SKILL.mdplugins/apple-dev-skills/skills/tipkit-workflow/agents/openai.yamlplugins/apple-dev-skills/skills/tipkit-workflow/references/customization-flow.mdplugins/apple-dev-skills/skills/tipkit-workflow/references/customization.template.yamlplugins/apple-dev-skills/skills/tipkit-workflow/references/eligibility-lifecycle-and-testing.mdplugins/apple-dev-skills/skills/tipkit-workflow/references/presentation-and-platform-patterns.mdplugins/apple-dev-skills/skills/tipkit-workflow/references/snippets/apple-xcode-project-core.mdplugins/apple-dev-skills/skills/tipkit-workflow/scripts/customization_config.pyplugins/apple-dev-skills/tests/test_apple_developer_provisioning_workflow.pyplugins/apple-dev-skills/tests/test_customization_consolidation_review.pyplugins/apple-dev-skills/tests/test_devicecheck_app_attest_workflow.pyplugins/apple-dev-skills/tests/test_tipkit_workflow.py
| - `sf-symbols-workflow` | ||
| - `structure-swift-sources` | ||
| - `swiftdata-workflow` | ||
| - `tipkit-workflow` |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Reconcile the Active Skills inventory count.
After adding tipkit-workflow, this README lists 35 skill entries (Lines 131–165), but .github/scripts/validate_repo_docs.sh and tests/test_tipkit_workflow.py require exactly 33. Align the README with the canonical 33-skill inventory, or update all registration and validation contracts consistently.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@plugins/apple-dev-skills/README.md` at line 153, Reconcile the skill
inventory centered on the README’s tipkit-workflow entry so the documented list
matches the canonical 33-skill count required by validate_repo_docs.sh and
test_tipkit_workflow.py. Prefer removing or correcting the extra inventory
entries to restore exactly 33, unless intentionally updating every registration
and validation contract consistently.
| def encode_scalar(value) -> str: | ||
| if isinstance(value, bool): | ||
| return "true" if value else "false" | ||
| if isinstance(value, int): | ||
| return str(value) | ||
| if value is None: | ||
| return quote_string("") | ||
| return quote_string(str(value)) |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Preserve scalar types during serialization.
validate_config() accepts floats and other scalar values, but encode_scalar() converts anything other than bool and int to a quoted string. A float setting therefore changes type after apply and reload.
Also applies to: 119-120
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@plugins/apple-dev-skills/skills/tipkit-workflow/scripts/customization_config.py`
around lines 38 - 45, Update encode_scalar to serialize supported scalar types
without converting them to quoted strings, especially preserving float values
through apply and reload. Retain the existing boolean, integer, None, and string
handling, and align the additional scalar cases with the types accepted by
validate_config().
| unknown = set(config.keys()) - ALLOWED_TOP_LEVEL | ||
| if unknown: | ||
| fail(f"Unknown top-level keys: {', '.join(sorted(unknown))}") |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Reject non-string mapping keys before sorting or regex validation.
YAML permits non-string keys. Such input can reach sorted(unknown) or re.fullmatch(..., key) and raise an uncaught TypeError instead of producing the CLI’s normal validation error.
Also applies to: 89-91
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@plugins/apple-dev-skills/skills/tipkit-workflow/scripts/customization_config.py`
around lines 71 - 73, Update the top-level and applicable nested key validation
around ALLOWED_TOP_LEVEL to detect non-string mapping keys before sorting
unknown keys or passing keys to regex validation. Route these cases through fail
with the CLI’s normal validation error, while preserving existing handling for
valid string keys.
| def dump_yaml(config: dict) -> str: | ||
| lines = [ | ||
| f"schemaVersion: {int(config['schemaVersion'])}", | ||
| f"isCustomized: {'true' if config['isCustomized'] else 'false'}", | ||
| "settings:", | ||
| ] | ||
| for key in sorted(config["settings"].keys()): | ||
| lines.append(f" {key}: {encode_scalar(config['settings'][key])}") | ||
| return "\n".join(lines) + "\n" |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Serialize an empty settings mapping as {}.
When config["settings"] is empty, this function emits:
settings:That parses as null, not a mapping, so the default effective output and an empty apply result cannot be loaded again by validate_config().
Proposed fix
def dump_yaml(config: dict) -> str:
+ if not config["settings"]:
+ return (
+ f"schemaVersion: {int(config['schemaVersion'])}\n"
+ f"isCustomized: {'true' if config['isCustomized'] else 'false'}\n"
+ "settings: {}\n"
+ )
lines = [🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@plugins/apple-dev-skills/skills/tipkit-workflow/scripts/customization_config.py`
around lines 113 - 121, Update dump_yaml to serialize an empty
config["settings"] mapping as “settings: {}” rather than emitting a bare
“settings:” line. Preserve the existing indented key serialization for non-empty
settings so validate_config() can reload both cases as mappings.
| target = durable_path() | ||
| target.parent.mkdir(parents=True, exist_ok=True) | ||
| target.write_text(dump_yaml(updated), encoding="utf-8") |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Write durable configuration atomically.
A process interruption during write_text() can leave a truncated or invalid customization file, causing subsequent effective and apply commands to fail. Write a temporary file in the same directory and replace the target with os.replace().
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@plugins/apple-dev-skills/skills/tipkit-workflow/scripts/customization_config.py`
around lines 173 - 175, Update the configuration write flow around
durable_path() to write dump_yaml(updated) to a temporary file in target.parent,
then atomically replace target using os.replace(). Preserve UTF-8 encoding and
ensure the temporary file is cleaned up if replacement fails.
| @@ -0,0 +1,75 @@ | |||
| --- | |||
| name: tipkit-workflow | |||
| description: Add, configure, present, style, test, and troubleshoot Apple TipKit tips in SwiftUI, UIKit, and AppKit using current Apple documentation. Use for Tip protocol definitions, Tips.configure, TipView inline tips, popoverTip tooltip popovers, TipUIView, TipUIPopoverViewController, TipNSView, TipNSPopover, rules, parameters, events and donations, actions, invalidation, display frequency, persistent datastores, testing overrides, and tips that do not appear or reappear correctly. | |||
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="plugins/apple-dev-skills/skills/tipkit-workflow/SKILL.md"
wc -l "$file"
cat -n "$file" | sed -n '1,40p'Repository: gaelic-ghost/socket
Length of output: 3781
🌐 Web query:
TipKit Apple documentation feature discovery onboarding guide cautions app flow
💡 Result:
Apple's TipKit framework is designed to provide contextual, non-intrusive feature discovery and onboarding [1][2]. Rather than traditional, front-loaded onboarding screens that users often ignore, TipKit allows developers to surface tips only when they are contextually relevant to a user's current activity [3][4]. Key guidelines and best practices for integrating TipKit into your app flow include: Focus on Contextual Relevance - Avoid showing tips immediately upon app launch [3]. Instead, trigger tips when a user is in the vicinity of a feature or has shown interest in it [3]. - Use eligibility rules (parameter-based or event-based) to ensure tips reach only the most relevant audience [5][6]. For example, only show a tip if a user has launched the app a minimum number of times or has not yet utilized a specific feature [3]. - Never describe the UI itself. Instead, focus on the user's outcome, such as the benefit they will gain from using the feature [3]. Maintain User Experience (UX) Quality - Use frequency control (e.g.,.daily or.hourly) to prevent tip fatigue [4]. Setting frequency to.immediate is suitable for development but generally discouraged for production [4]. - Always invalidate tips after a user has successfully engaged with the feature being taught [4][6]. Failing to do so can result in redundant, frustrating displays [4]. - Be mindful of tip order. Use.ordered to show tips in a specific sequence, or.firstAvailable to display the most relevant tip when multiple are eligible [4]. Implementation and Testing - Configure the Tips system at app launch using Tips.configure [7][6]. - During development, leverage TipKit's testing functions, such as Tips.showTipsForTesting(_:), to bypass eligibility rules and verify UI presentation [7]. - Ensure your copy is concise and follows Apple's Human Interface Guidelines for "Offering Help," using sentence case and clear, actionable language [8]. By treating tips as data (structs with titles, messages, and rules) and allowing the framework to manage their presentation state, you can create a more educational and less intrusive app experience [4].
Citations:
- 1: https://developer.apple.com/documentation/tipkit/
- 2: https://developer.apple.com/videos/play/wwdc2023/10229/
- 3: https://rorklab.net/en/articles/rork-dev/rork-max-tipkit-in-app-guidance-onboarding-complete-guide
- 4: https://swiftcrafted.dev/article/tipkit-swiftui-complete-guide-in-app-tips-onboarding-user-education-ios-26
- 5: https://developer.apple.com/videos/play/wwdc2023/10229
- 6: https://bendodson.com/weblog/2023/07/26/tipkit-tutorial/
- 7: https://developer.apple.com/documentation/tipkit/tips/showtipsfortesting(_:)
- 8: https://apple-docs.everest.mt/docs/design/human-interface-guidelines/offering-help/
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="plugins/apple-dev-skills/skills/tipkit-workflow/SKILL.md"
printf 'FILE: %s\n' "$file"
nl -ba "$file" | sed -n '1,30p'Repository: gaelic-ghost/socket
Length of output: 260
🌐 Web query:
site:developer.apple.com TipKit feature discovery onboarding app flow
💡 Result:
TipKit is the recommended framework by Apple for implementing feature discovery and contextual onboarding within iOS and other platform apps [1][2]. Instead of relying solely on traditional, front-loaded onboarding flows, Apple’s Human Interface Guidelines suggest providing a collection of context-specific tips to teach users about features as they encounter them [3][2]. Key components for implementing feature discovery with TipKit include: Contextual Integration: Tips are designed to be displayed at the "perfect moment" when a user is likely to need or appreciate the information, rather than interrupting the user immediately upon launch [4]. Tip Groups: You can use TipGroup to sequence tips, ensuring features are discovered in an ideal, structured order [4]. This helps manage the educational flow and prevents overwhelming the user. Eligibility and Rules: TipKit manages display states and history automatically, but you retain control through eligibility rules. You can use these rules to ensure tips only appear to relevant users (e.g., users who have not used a specific feature yet) [4]. Display Frequency: To maintain a positive user experience, you can set a global display frequency (e.g., daily or weekly) using Tips.configure(_:) to ensure users are not bombarded with too many tips in a short timeframe [4][5]. Customization: TipKit supports custom tip identifiers, which allow for reusable tips (e.g., creating unique tips for dynamic content like new items in a list), and offers configurable presentation styles (TipViewStyle) to ensure the UI matches your app’s design [4][6]. CloudKit Syncing: You can sync the TipKit datastore via CloudKit to share tip display states across a user's devices, preventing the same tip from appearing on multiple devices once it has been dismissed or viewed on one [4]. For further guidance, Apple provides detailed resources in their documentation and session videos, specifically WWDC23 "Make features discoverable with TipKit" and WWDC24 "Customize feature discovery with TipKit" [4][7].
Citations:
- 1: https://developer.apple.com/documentation/tipkit/
- 2: https://developer.apple.com/design/human-interface-guidelines/offering-help
- 3: https://developer.apple.com/design/human-interface-guidelines/onboarding
- 4: https://developer.apple.com/videos/play/wwdc2024/10070/
- 5: https://developer.apple.com/documentation/tipkit/tips/configurationoption/displayfrequency(_:)
- 6: https://developer.apple.com/documentation/tipkit/tip/id
- 7: https://developer.apple.com/videos/play/wwdc2023/10229/
Remove “onboarding” from the TipKit guidance. TipKit is for contextual feature discovery; phrasing it as onboarding can steer authors toward using it as a full onboarding flow instead of a dedicated onboarding experience.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@plugins/apple-dev-skills/skills/tipkit-workflow/SKILL.md` at line 3, Update
the TipKit skill description to remove the term “onboarding” and any
onboarding-oriented guidance, while preserving its contextual feature-discovery
scope and all existing TipKit symbols and workflows.
Summary
Verification
uv run --directory plugins/apple-dev-skills pytest(201 passed)bash plugins/apple-dev-skills/.github/scripts/validate_repo_docs.shuv run scripts/validate_socket_metadata.pySummary by CodeRabbit
New Features
Tests