skills/generators/feedback-form/SKILL.md
Generates an in-app feedback collection form with category selection, text input, optional screenshot attachment, device diagnostics, and smart routing — directing happy users to App Store reviews and unhappy users to support. Use when user wants feedback, bug reports, feature requests, or contact support forms.
npx skillsauth add rshankras/claude-code-apple-skills feedback-formInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generate a production in-app feedback form with category selection, sentiment-based rating, optional screenshot attachment, device diagnostics collection, and smart routing that funnels satisfied users to the App Store review prompt and dissatisfied users to a support channel.
Use this skill when the user:
Search for existing feedback or support code:
Glob: **/*Feedback*.swift, **/*Support*.swift, **/*BugReport*.swift, **/*ContactForm*.swift
Grep: "MFMailComposeViewController" or "FeedbackForm" or "SKStoreReviewController"
If third-party feedback SDK found (Instabug, UserVoice, Zendesk):
Check for MessageUI availability:
Grep: "import MessageUI" or "MFMailCompose"
Note: MessageUI is iOS-only. macOS uses NSSharingService or direct webhook delivery.
Ask user via AskUserQuestion:
Feedback categories? (multi-select)
Delivery method?
Include screenshot capture?
Include device diagnostics?
Sentiment routing?
Read templates.md for production Swift code.
Generate these files:
FeedbackCategory.swift — Enum with SF Symbol icons and display namesFeedbackEntry.swift — Data model for a feedback submissionDeviceDiagnostics.swift — Collects device and app infoFeedbackFormView.swift — SwiftUI form with sentiment, category, message, screenshotsFeedbackSubmitter.swift — Protocol + EmailFeedbackSubmitter + WebhookFeedbackSubmitterBased on configuration:
ScreenshotCapture.swift — If screenshot capture selectedCheck project structure:
Sources/ exists -> Sources/Feedback/App/ exists -> App/Feedback/Feedback/After generation, provide:
Feedback/
├── FeedbackCategory.swift # Category enum with icons
├── FeedbackEntry.swift # Feedback data model
├── DeviceDiagnostics.swift # Device info collector
├── FeedbackFormView.swift # SwiftUI form view
├── FeedbackSubmitter.swift # Email + webhook delivery
└── ScreenshotCapture.swift # Screen capture (optional)
Present the feedback form from any view:
@State private var showFeedback = false
Button("Send Feedback") {
showFeedback = true
}
.sheet(isPresented: $showFeedback) {
FeedbackFormView()
}
In a settings screen:
Form {
Section("Support") {
Button {
showFeedback = true
} label: {
Label("Send Feedback", systemImage: "bubble.left.and.text.bubble.right")
}
}
}
.sheet(isPresented: $showFeedback) {
FeedbackFormView()
}
With a pre-selected category (e.g., from a help menu):
FeedbackFormView(initialCategory: .bugReport)
@Test
func feedbackEntryEncodesCorrectly() throws {
let entry = FeedbackEntry(
category: .bugReport,
message: "App crashes when tapping save",
rating: 2,
screenshots: [],
deviceInfo: DeviceDiagnostics.collect(),
appVersion: "1.2.3",
timestamp: Date()
)
let data = try JSONEncoder().encode(entry)
let decoded = try JSONDecoder().decode(FeedbackEntry.self, from: data)
#expect(decoded.category == .bugReport)
#expect(decoded.rating == 2)
}
@Test
func webhookSubmitterSendsCorrectPayload() async throws {
let mockSession = MockURLSession()
let submitter = WebhookFeedbackSubmitter(
url: URL(string: "https://example.com/feedback")!,
session: mockSession
)
let entry = FeedbackEntry(
category: .featureRequest,
message: "Dark mode support please",
rating: 4,
screenshots: [],
deviceInfo: DeviceDiagnostics.collect(),
appVersion: "1.0.0",
timestamp: Date()
)
try await submitter.submit(entry)
#expect(mockSession.lastRequest?.httpMethod == "POST")
#expect(mockSession.lastRequest?.value(forHTTPHeaderField: "Content-Type") == "application/json")
}
@Test
func sentimentRoutingDirectsHighRatingToReview() {
let entry = FeedbackEntry(
category: .praise,
message: "Love this app!",
rating: 5,
screenshots: [],
deviceInfo: DeviceDiagnostics.collect(),
appVersion: "1.0.0",
timestamp: Date()
)
#expect(entry.suggestsAppStoreReview) // rating >= 4
}
Button {
showFeedback = true
NSApp.activate(ignoringOtherApps: true)
} label: {
Label("Send Feedback", systemImage: "envelope")
}
.sheet(isPresented: $showFeedback) {
FeedbackFormView()
}
let screenshot = try await ScreenshotCapture.captureCurrentWindow()
let entry = FeedbackEntry(
category: .bugReport,
message: "Layout is broken on this screen",
rating: 1,
screenshots: [screenshot],
deviceInfo: DeviceDiagnostics.collect(),
appVersion: Bundle.main.appVersion,
timestamp: Date()
)
try await submitter.submit(entry)
if entry.suggestsAppStoreReview {
// Happy user — ask for App Store review
if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
SKStoreReviewController.requestReview(in: scene)
}
} else if entry.suggestsSupportFollowUp {
// Unhappy user — show support confirmation
showSupportConfirmation = true
}
MFMailComposeViewController.canSendMail() before presenting. Fall back to webhook or mailto: URL if unavailable.UITextField.isSecureTextEntry areas as a guide.NWPathMonitor to detect network changes.SKStoreReviewController.requestReview() is rate-limited by the system (typically 3 times per 365-day period). Don't rely on it always appearing.NSSharingService(named: .composeEmail) or prefer webhook delivery on macOS.generators/review-prompt — App Store review prompt timing and strategydevelopment
US web checkout via the StoreKit External Purchase Link entitlement — currently 0% Apple commission (litigation ongoing), how to ship it safely, and how to architect for a commission flip so a future ruling is a config change, not a rewrite. Use when adding external purchase links, weighing web checkout vs IAP, or planning US-storefront pricing strategy.
tools
Revenue beyond the single-app price tag — own-app bundles, Family Sharing as a conversion lever, cross-developer bundles & suites, and institutional licensing via Group Purchases / Apple School & Business Manager. Use when a developer has multiple apps, a subscription worth sharing, complementary indie partners, or school/clinic/business buyers.
testing
Run a structured accessibility audit on an iOS/macOS app — automated XCUITest audits, Accessibility Inspector, manual VoiceOver/Dynamic Type passes, and App Store Accessibility Nutrition Label evaluation. Use before release, when preparing Nutrition Label declarations, or for EU Accessibility Act compliance.
tools
Stage-by-stage audit of an app's App Store growth machinery against a 54-item P0–P9 playbook — every item scored from an App Store Connect MCP call, a codebase check, or an explicit question to the user, then routed to the skill or command that fixes it. Read-only on App Store Connect. Use for a growth audit or scorecard, a pre-launch growth plan, a quarterly re-audit, or "which growth levers am I missing."