plugin: add Tips HelpViewer workflow#135
Conversation
📝 WalkthroughWalkthroughAdds the Tips/HelpViewer local guide discovery skill, its agent configuration, fallback and customization contracts, a configuration CLI, and repository metadata and test updates for 50 active skills. ChangesTips HelpViewer workflow
Sequence Diagram(s)sequenceDiagram
participant Requester
participant TipsHelpViewerWorkflow
participant HelpViewerCatalog
participant FallbackDocumentation
Requester->>TipsHelpViewerWorkflow: request local guide
TipsHelpViewerWorkflow->>HelpViewerCatalog: search installed app catalog
HelpViewerCatalog-->>TipsHelpViewerWorkflow: matching or incomplete guide result
TipsHelpViewerWorkflow->>FallbackDocumentation: use ordered fallback when needed
FallbackDocumentation-->>Requester: guide result with source provenance
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: 3
🤖 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 176: Reconcile the Active Skills inventory in README.md with the
canonical count of 50 enforced by validate_repo_docs.sh. Review the entries
across the Active Skills section, remove stale or non-active entries as needed,
and ensure the final list contains exactly 50 skills while retaining valid
active skills.
In
`@plugins/apple-dev-skills/skills/tips-helpviewer-workflow/scripts/customization_config.py`:
- Around line 113-121: Update dump_yaml to serialize an empty config["settings"]
mapping explicitly as an empty YAML map while preserving the existing key
serialization for non-empty settings. Also update parse_yaml to normalize a
missing or null settings value to an empty mapping before validate_config,
ensuring durable round-trips with empty or fully reset settings succeed.
In `@plugins/apple-dev-skills/tests/test_milestone24_system_ui_workflows.py`:
- Around line 57-69: Update
test_tips_helpviewer_workflow_requires_a_local_match_and_owner_aware_fallback to
read the skill’s customization_config.py and assert it contains the expected
SKILL_NAME = "tips-helpviewer-workflow" declaration, matching the verification
pattern used by test_app_intents_workflow and test_liquid_glass_workflow.
🪄 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: 4bbaeace-466b-4190-8956-8d05d2e869fa
📒 Files selected for processing (24)
ROADMAP.mdplugins/apple-dev-skills/.codex-plugin/plugin.jsonplugins/apple-dev-skills/.github/scripts/validate_repo_docs.shplugins/apple-dev-skills/README.mdplugins/apple-dev-skills/docs/maintainers/customization-consolidation-review.mdplugins/apple-dev-skills/skills/tips-helpviewer-workflow/SKILL.mdplugins/apple-dev-skills/skills/tips-helpviewer-workflow/agents/openai.yamlplugins/apple-dev-skills/skills/tips-helpviewer-workflow/references/catalog-and-fallback-contract.mdplugins/apple-dev-skills/skills/tips-helpviewer-workflow/references/customization-flow.mdplugins/apple-dev-skills/skills/tips-helpviewer-workflow/references/customization.template.yamlplugins/apple-dev-skills/skills/tips-helpviewer-workflow/references/snippets/apple-xcode-project-core.mdplugins/apple-dev-skills/skills/tips-helpviewer-workflow/scripts/customization_config.pyplugins/apple-dev-skills/tests/test_apple_developer_provisioning_workflow.pyplugins/apple-dev-skills/tests/test_arkit_spatial_face_body_workflows.pyplugins/apple-dev-skills/tests/test_camera_capture_depth_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_imaging_foundation_workflows.pyplugins/apple-dev-skills/tests/test_milestone24_system_ui_workflows.pyplugins/apple-dev-skills/tests/test_photos_library_editing_workflow.pyplugins/apple-dev-skills/tests/test_tipkit_workflow.pyplugins/apple-dev-skills/tests/test_video_codec_processing_workflow.pyplugins/apple-dev-skills/tests/test_vision_recognition_workflows.pyplugins/apple-dev-skills/tests/test_xcode_localization_workflow.py
| - `structure-swift-sources` | ||
| - `swiftdata-workflow` | ||
| - `tipkit-workflow` | ||
| - `tips-helpviewer-workflow` |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Reconcile the README inventory with the canonical active-skill count.
The Active Skills section currently contains 57 entries across Lines 142-198, while validate_repo_docs.sh and related documentation declare 50 active skills. Adding this entry without reconciling the stale entries leaves the public inventory inconsistent.
🤖 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 176, Reconcile the Active Skills
inventory in README.md with the canonical count of 50 enforced by
validate_repo_docs.sh. Review the entries across the Active Skills section,
remove stale or non-active entries as needed, and ensure the final list contains
exactly 50 skills while retaining valid active skills.
| 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
dump_yaml produces unparseable YAML when settings is empty.
When config["settings"] is {}, dump_yaml emits settings: with no value, which YAML parses as null — not an empty mapping. A subsequent load_durable() → parse_yaml() → validate_config() then fails with "settings must be a mapping" because None is not a dict. This corrupts the durable config round-trip: apply with empty (or fully-reset) settings writes a file that effective cannot read back.
🐛 Proposed fix for dump_yaml and parse_yaml
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])}")
+ if config["settings"]:
+ lines.append("settings:")
+ for key in sorted(config["settings"].keys()):
+ lines.append(f" {key}: {encode_scalar(config['settings'][key])}")
+ else:
+ lines.append("settings: {}")
return "\n".join(lines) + "\n"Also harden parse_yaml to defensively normalize None settings:
if isinstance(loaded.get("settings"), dict):
loaded["settings"] = {
key: ("" if value is None else value) for key, value in loaded["settings"].items()
}
+ elif loaded.get("settings") is None:
+ loaded["settings"] = {}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 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" | |
| def dump_yaml(config: dict) -> str: | |
| lines = [ | |
| f"schemaVersion: {int(config['schemaVersion'])}", | |
| f"isCustomized: {'true' if config['isCustomized'] else 'false'}", | |
| ] | |
| if config["settings"]: | |
| lines.append("settings:") | |
| for key in sorted(config["settings"].keys()): | |
| lines.append(f" {key}: {encode_scalar(config['settings'][key])}") | |
| else: | |
| lines.append("settings: {}") | |
| return "\n".join(lines) + "\n" |
🤖 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/tips-helpviewer-workflow/scripts/customization_config.py`
around lines 113 - 121, Update dump_yaml to serialize an empty
config["settings"] mapping explicitly as an empty YAML map while preserving the
existing key serialization for non-empty settings. Also update parse_yaml to
normalize a missing or null settings value to an empty mapping before
validate_config, ensuring durable round-trips with empty or fully reset settings
succeed.
| def test_tips_helpviewer_workflow_requires_a_local_match_and_owner_aware_fallback(self) -> None: | ||
| skill = self.read("skills/tips-helpviewer-workflow/SKILL.md") | ||
| reference = self.read("skills/tips-helpviewer-workflow/references/catalog-and-fallback-contract.md") | ||
| prompt = self.read("skills/tips-helpviewer-workflow/agents/openai.yaml") | ||
|
|
||
| self.assertIn("com.apple.helpviewer", skill) | ||
| self.assertIn("com.apple.tips", skill) | ||
| self.assertIn("installed-version capture", skill) | ||
| self.assertIn("local-helpviewer", skill) | ||
| self.assertIn("Do not modify app settings", skill) | ||
| self.assertIn("Compressor export movie", reference) | ||
| self.assertIn("explore-apple-swift-docs", reference) | ||
| self.assertIn("$tips-helpviewer-workflow", prompt) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add customization script verification to match sibling test pattern.
The test_app_intents_workflow and test_liquid_glass_workflow tests in this file both read the skill's customization_config.py and assert SKILL_NAME = "...". This test omits that check, breaking the established pattern.
💚 Proposed fix
def test_tips_helpviewer_workflow_requires_a_local_match_and_owner_aware_fallback(self) -> None:
skill = self.read("skills/tips-helpviewer-workflow/SKILL.md")
reference = self.read("skills/tips-helpviewer-workflow/references/catalog-and-fallback-contract.md")
prompt = self.read("skills/tips-helpviewer-workflow/agents/openai.yaml")
+ customization = self.read("skills/tips-helpviewer-workflow/scripts/customization_config.py")
self.assertIn("com.apple.helpviewer", skill)
self.assertIn("com.apple.tips", skill)
self.assertIn("installed-version capture", skill)
self.assertIn("local-helpviewer", skill)
self.assertIn("Do not modify app settings", skill)
self.assertIn("Compressor export movie", reference)
self.assertIn("explore-apple-swift-docs", reference)
self.assertIn("$tips-helpviewer-workflow", prompt)
+ self.assertIn('SKILL_NAME = "tips-helpviewer-workflow"', customization)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def test_tips_helpviewer_workflow_requires_a_local_match_and_owner_aware_fallback(self) -> None: | |
| skill = self.read("skills/tips-helpviewer-workflow/SKILL.md") | |
| reference = self.read("skills/tips-helpviewer-workflow/references/catalog-and-fallback-contract.md") | |
| prompt = self.read("skills/tips-helpviewer-workflow/agents/openai.yaml") | |
| self.assertIn("com.apple.helpviewer", skill) | |
| self.assertIn("com.apple.tips", skill) | |
| self.assertIn("installed-version capture", skill) | |
| self.assertIn("local-helpviewer", skill) | |
| self.assertIn("Do not modify app settings", skill) | |
| self.assertIn("Compressor export movie", reference) | |
| self.assertIn("explore-apple-swift-docs", reference) | |
| self.assertIn("$tips-helpviewer-workflow", prompt) | |
| def test_tips_helpviewer_workflow_requires_a_local_match_and_owner_aware_fallback(self) -> None: | |
| skill = self.read("skills/tips-helpviewer-workflow/SKILL.md") | |
| reference = self.read("skills/tips-helpviewer-workflow/references/catalog-and-fallback-contract.md") | |
| prompt = self.read("skills/tips-helpviewer-workflow/agents/openai.yaml") | |
| customization = self.read("skills/tips-helpviewer-workflow/scripts/customization_config.py") | |
| self.assertIn("com.apple.helpviewer", skill) | |
| self.assertIn("com.apple.tips", skill) | |
| self.assertIn("installed-version capture", skill) | |
| self.assertIn("local-helpviewer", skill) | |
| self.assertIn("Do not modify app settings", skill) | |
| self.assertIn("Compressor export movie", reference) | |
| self.assertIn("explore-apple-swift-docs", reference) | |
| self.assertIn("$tips-helpviewer-workflow", prompt) | |
| self.assertIn('SKILL_NAME = "tips-helpviewer-workflow"', customization) |
🤖 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_milestone24_system_ui_workflows.py`
around lines 57 - 69, Update
test_tips_helpviewer_workflow_requires_a_local_match_and_owner_aware_fallback to
read the skill’s customization_config.py and assert it contains the expected
SKILL_NAME = "tips-helpviewer-workflow" declaration, matching the verification
pattern used by test_app_intents_workflow and test_liquid_glass_workflow.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4a70439333
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "name": "apple-dev-skills", | ||
| "version": "9.5.0", | ||
| "description": "Apple development workflows for Codex, including App Intents, Liquid Glass, PhotosUI/PhotoKit, VideoToolbox codecs, ARKit spatial/face/body sensing, camera/depth capture, Core Image, Image I/O, Vision/Core ML recognition, media/audio repair, provisioning, CloudKit, TipKit, SwiftData, SwiftUI, XcodeGen, Core Animation, AppKit, Safari, security, OpenAPI, and DocC.", | ||
| "description": "Apple development workflows for Codex, including App Intents, Liquid Glass, PhotosUI/PhotoKit, VideoToolbox codecs, ARKit spatial/face/body sensing, camera/depth capture, Core Image, Image I/O, Vision/Core ML recognition, media/audio repair, local Tips/HelpViewer guide discovery, provisioning, CloudKit, TipKit, SwiftData, SwiftUI, XcodeGen, Core Animation, AppKit, Safari, security, OpenAPI, and DocC.", |
There was a problem hiding this comment.
Add HelpViewer to interface metadata
This registers the new Tips/HelpViewer skill in the package description and keywords, but the interface.longDescription and interface.defaultPrompt below still omit any local guide discovery prompt. In marketplace/composer surfaces that render the interface metadata, users will not see or be steered toward the new workflow even though the README and active-skill validator now advertise it.
Useful? React with 👍 / 👎.
Summary
tips-helpviewer-workflowfor verified local Apple app guide discoveryVerification
pytest(249 passed)pytest(81 passed, 1 skipped)Summary by CodeRabbit
New Features
Documentation
Tests