skills/app-polish/SKILL.md
--- name: app-polish description: Post-ship launch-ready polish audit. Walks a freshly-shipped web app against the ten-point launch-polish checklist (analytics, stats surface, OG images, PWA, SEO, keyboard, accessibility, visual regression, API docs, craft signals) and routes to the dedicated sub-skill for each gap. Use right after `/ro:cf-ship` / `/ro:fly-deploy` / `/ro:gh-ship`, or before a Product Hunt / Show HN launch. category: quality-review argument-hint: [--app <dir>] [--only <checks>] [
npx skillsauth add RonanCodes/ronan-skills skills/app-polishInstall 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.
Pre-launch audit for a web app. Walks ten checks in order; for each gap, routes to a dedicated sub-skill that actually does the work. Designed to run on the Friday before a Tuesday / Wednesday launch.
/ro:app-polish # audit current repo, report gaps
/ro:app-polish --app ./connections-helper
/ro:app-polish --only analytics,og # run only a subset
/ro:app-polish --skip pwa,visual-reg # skip items not applicable
/ro:app-polish --fix # auto-invoke each sub-skill for gaps found
Report format per check:
[✓|⚠|✗] <check> — <one-line finding>
Sub-skill: /ro:<skill>
Effort: <S|M|L>
Launch impact: <high|medium|low>
Run in this order (earlier items compound into later ones — e.g. analytics events need to exist before visual regression baselines get captured).
/ro:posthogIs there an analytics provider wired up? Are custom events fired on share handlers, CTAs, forms? Is there a typed track() wrapper?
Detect:
grep -rn "posthog.init\|plausible.init\|Mixpanel" src 2>&1 | head -3
grep -rn "posthog.capture\|track(" src 2>&1 | wc -l
Verdict rules:
track() wrapper exists + share/cta/form events fired.Fix: invoke /ro:posthog install if missing, then see the "Launch-ready event instrumentation" section for the event checklist.
Is there a stats endpoint (counts, usage, reach) and is it displayed in the UI? Numbers on a page are a low-cost trust signal.
Detect:
grep -rn "/api/stats\|/api/metrics\|/api/health" src --include='*.ts' --include='*.tsx' | head
grep -rn "toLocaleString\|stats\." src/routes src/components 2>&1 | head
Verdict rules:
Fix: add a StatsBanner component (see seo-launch-ready for template) that fetch('/api/stats') + renders counts with toLocaleString(). Keep it aria-live="polite".
/ro:og-image-dynamicEvery share-target URL should unfurl with a distinct Open Graph image. Generic static OG kills click-through on Twitter/Reddit/LinkedIn previews.
Detect:
grep -rn 'og:image\|twitter:image' src 2>&1 | head
ls -la public/*.png 2>&1 | head
Verdict:
og-image.png for all URLs./api/og.png (or similar) exists and meta tags reference a per-URL variant.Fix: /ro:og-image-dynamic — Satori + Cloudflare Workers or Vercel OG template.
/ro:pwa-installDaily-return apps (puzzles, habit trackers, dashboards) should be installable. Replaces the need for an email list.
Detect:
ls public/manifest.json public/manifest.webmanifest 2>&1
ls public/sw.js public/service-worker.js 2>&1
grep -rn 'link.*rel="manifest"' src 2>&1 | head -3
Verdict:
Fix: /ro:pwa-install.
/ro:seo-launch-readySitemap, robots.txt, JSON-LD structured data, canonical URLs, meta tags complete across all routes.
Detect:
ls public/sitemap.xml public/robots.txt 2>&1
grep -rn 'application/ld+json\|canonical\|og:title' src 2>&1 | head
Verdict:
Fix: /ro:seo-launch-ready.
/ro:keyboard-shortcutsPower-user signal that drives screencasts and portfolio respect. Especially for utility apps.
Detect:
grep -rn "addEventListener.*keydown\|useHotkeys\|useKeyboard" src 2>&1 | head -3
Verdict:
? brings up a shortcut list and main actions have bindings.Fix: /ro:keyboard-shortcuts.
/ro:accessibility-ciaria-live regions on async state, focus management in modals, colour contrast, axe-core unit + e2e, Lighthouse CI.
Detect:
grep -rn 'aria-live\|aria-label\|role=' src 2>&1 | wc -l
grep -l 'axe-core\|@axe-core/playwright\|jest-axe' package.json 2>&1
ls .github/workflows 2>&1 | head
Verdict:
aria-live on any async region, or axe-core not in deps.Fix: /ro:accessibility-ci.
/ro:visual-regressionPlaywright screenshot baselines + PR diff comments. Protects the polish work from silent CSS regressions.
Detect:
grep -rn 'toHaveScreenshot\|pixelmatch\|percy' tests e2e 2>&1 | head
Verdict:
toHaveScreenshot assertions.Fix: /ro:visual-regression.
Scalar / Swagger / Redoc docs exposed and linked from the footer. Craft signal.
Detect:
grep -rn '/api/docs\|/api/openapi\|@scalar\|swagger-ui' src 2>&1 | head
grep -rn 'footer.*API\|footer.*docs' src 2>&1 | head
Verdict:
/how-it-works has a visible link.Fix: add <a href="/api/docs" target="_blank">API</a> in the footer.
Miscellaneous polish: robots meta, canonical URL, 404 page, aria-label on all icon-only buttons, environment-specific favicon (optional), skip-to-content link.
Detect:
grep -rn 'skip.*content\|skip.*main' src 2>&1 | head
find src -name 'not-found*' -o -name '404*' 2>&1 | head
grep -rn '<Button[^>]*onClick' src/App.tsx | grep -v 'aria-label\|title' | head
Verdict:
aria-label, or no 404 route.Fix: spot-fix, no dedicated sub-skill.
#!/usr/bin/env bash
# /ro:app-polish implementation sketch
set -euo pipefail
APP=${1:-.}
cd "$APP"
echo "=== App Polish Audit: $(pwd) ==="
echo
# 1. Analytics
if grep -rn "posthog.init\|plausible.init" src >/dev/null 2>&1; then
events=$(grep -rn "track(\|posthog.capture" src 2>/dev/null | wc -l | tr -d ' ')
if [ "$events" -ge 3 ]; then
echo "[✓] analytics — provider + $events custom event call sites"
else
echo "[⚠] analytics — provider wired but only $events custom events (need ≥3)"
echo " Sub-skill: /ro:posthog · Effort: S · Impact: high"
fi
else
echo "[✗] analytics — no provider detected"
echo " Sub-skill: /ro:posthog · Effort: S · Impact: high"
fi
# ...(repeat for 2-10)
The --fix flag invokes the sub-skill for each ⚠ or ✗ in sequence, with a confirmation prompt per skill.
| Existing skill | Role in polish |
| --- | --- |
| /ro:close-the-loop | Runs the app's own test suite; polish is what to run on top of tests passing. |
| /ro:playwright-check | Underlying browser tool; visual-regression uses it for baselines. |
| /ro:visual-diff | Per-image pixel diff; visual-regression composes this into a CI flow. |
| /ro:design-system-audit | Deeper audit of colour tokens, spacing, typography. Run alongside app-polish for the visual axis. |
| /ro:security-audit | Secrets, headers, rate limits, CSP. Complementary to polish. |
| /ro:cf-ship / /ro:fly-deploy / /ro:gh-ship | What ships the app; app-polish runs right after a successful ship, before the marketing beat. |
--fix. The user should pick which gaps to close./ro:close-the-loop is the per-PR gate./ro:posthog — analytics + event instrumentation/ro:og-image-dynamic — per-URL Open Graph images/ro:pwa-install — manifest + service worker/ro:seo-launch-ready — sitemap + JSON-LD + meta/ro:keyboard-shortcuts — global key handler/ro:accessibility-ci — axe + Lighthouse + a11y unit tests/ro:visual-regression — Playwright screenshot baselines/ro:design-system-audit — visual invariants/ro:security-audit — CSP, secrets, rate limiting/ro:close-the-loop — per-PR verification, complements polishtesting
--- name: linear-pipeline description: The Fable orchestrator for a single dispatched Linear ticket. Holds almost no context itself; it receives `--issue <ID> --detached`, decides the stage sequence, and fans out a sub-agent per stage, passing forward only each stage's artifact (never re-derived, never inlined into its own context). Step zero, before any planning or stage routing, is a boundary triage against `canon/security-boundary.md` (#199): a match tags Ronan Connolly and stops the run, no
development
--- name: in-your-face description: Capture a chat-only answer into a durable artifact (markdown + HTML, PDF when cheap) and launch it automatically so the user cannot miss it. Use when user says "in your face", "don't let me lose this", "save that answer", "make that durable", or right after answering a substantive side question (a recipe, comparison, how-to, or generated prompt) that would otherwise die with the context. category: workflow argument-hint: [--no-open] [--vault <short>] [hint of
tools
One-shot headless OpenAI Codex CLI calls for background/admin AI tasks — summaries, classification, extraction, admin glue. The default engine for anything that runs AI constantly in the background (daemon-driven, per-event), because it bills the flat ChatGPT subscription instead of Claude usage or per-token API spend, and it keeps working while Claude is rate-limited. NEVER for coding — coding stays Claude. Use when a skill or daemon needs a cheap always-on AI call, when the user says "use codex", "ask codex", "codex as backup", or when building a background summarizer/classifier into a listener or loop. Reads auth from ~/.codex/auth.json (ChatGPT account, no API key).
research
Turn a warranty rejection, repair quote, or RMA email into a cited decision brief — legal read (NL/EU consumer law), is the part user-serviceable, live part and new-unit prices, repair-vs-DIY-vs-new economics, before-you-send-it checklist, deadlines. Use when the user pastes or screenshots a repair quote, warranty rejection, "not covered" email, onderzoekskosten fee, or asks "should I repair or replace this".