app_open_clean
Open a macOS app AND dismiss any blocking welcome / "What's New" / setup-prompt sheet that appeared on launch. Returns the app name and whether a modal was dismissed. Use this INSTEAD of `shell open -a X` when first opening an app you haven't driven before — saves the agent from the common failure mode of typing into a welcome modal instead of the actual UI. Looks for these dismiss buttons in priority order across any sheet or window of the frontmost app: Continue · Get Started · Skip · Later · Not Now · Got It · Maybe Later · Done · Cancel Generic — works for first-launch Apple apps (Reminders, Mail, Calendar, Photos, Maps, Music) and third-party apps that follow the same modal pattern.
- License 许可
- Apache-2.0
- 最近更新
- 2026-11-01
- Stars
- ★ 9
- Forks
- 3
01 前言 Front Matter
- args
- [ "{{app}}" ]
- name
- app_open_clean
- schema
- { "app": { "type": "string", "required": true, "description": "App name (e.g. \"Reminders\", \"Mail\", \"Calendar\") or bundle ID. Whatever `open -a` accepts." } }
- command
- [ "sh", "-c", "APP=\"$1\"\n[ -z \"$APP\" ] && { echo \"app name required\" >&2; exit 1; }\n\nopen -a \"$APP\"\n# Most welcome sheets appear within 1.5s of launch. Sleep more on\n# slow boots — better to be late than to dismiss-before-render.\nsleep 1.5\n\n# Walk the frontmost app's sheets + windows; click the first\n# matching dismiss button by priority. Errors silenced — if the\n# app has no modal, we just exit with no-op success.\nDISMISSED=$(osascript 2>/dev/null <<'APPLESCRIPT'\nset dismissBtns to {\"Continue\", \"Get Started\", \"Skip\", \"Later\", \"Not Now\", \"Got It\", \"Maybe Later\", \"Done\", \"Cancel\"}\nset didClick to \"\"\ntell application \"System Events\"\n try\n set frontProc to first application process whose frontmost is true\n tell frontProc\n repeat with w in windows\n -- Sheets (attached modal dialogs)\n try\n repeat with s in sheets of w\n repeat with btnName in dismissBtns\n if exists (button btnName of s) then\n click button btnName of s\n set didClick to btnName as string\n exit repeat\n end if\n end repeat\n if didClick is not \"\" then exit repeat\n end repeat\n end try\n if didClick is not \"\" then exit repeat\n -- Standalone window that looks like welcome (has Continue/Get Started)\n try\n repeat with btnName in {\"Continue\", \"Get Started\", \"Got It\"}\n if exists (button btnName of w) then\n click button btnName of w\n set didClick to btnName as string\n exit repeat\n end if\n end repeat\n end try\n if didClick is not \"\" then exit repeat\n end repeat\n end tell\n end try\nend tell\nreturn didClick\nAPPLESCRIPT\n)\n\n# Some welcome flows are multi-step. Run a second pass to catch\n# the next sheet (e.g. Reminders has \"What's New\" → may auto-open\n# iCloud sync prompt). Quick second pass, no sleep needed.\nif [ -n \"$DISMISSED\" ]; then\n sleep 0.4\n DISMISSED2=$(osascript 2>/dev/null <<'APPLESCRIPT'\nset dismissBtns to {\"Continue\", \"Get Started\", \"Skip\", \"Later\", \"Not Now\", \"Got It\", \"Maybe Later\", \"Done\", \"Cancel\"}\nset didClick to \"\"\ntell application \"System Events\"\n try\n set frontProc to first application process whose frontmost is true\n tell frontProc\n repeat with w in windows\n try\n repeat with s in sheets of w\n repeat with btnName in dismissBtns\n if exists (button btnName of s) then\n click button btnName of s\n set didClick to btnName as string\n exit repeat\n end if\n end repeat\n if didClick is not \"\" then exit repeat\n end repeat\n end try\n if didClick is not \"\" then exit repeat\n end repeat\n end tell\n end try\nend tell\nreturn didClick\nAPPLESCRIPT\n)\nfi\n\nif [ -n \"$DISMISSED\" ]; then\n printf 'opened: %s\\ndismissed: %s' \"$APP\" \"$DISMISSED\"\n [ -n \"$DISMISSED2\" ] && printf ' → %s' \"$DISMISSED2\"\n printf '\\n'\nelse\n printf 'opened: %s\\ndismissed: (no modal found)\\n' \"$APP\"\nfi\n", "_" ]
- timeout
- 15
- description
- Open a macOS app AND dismiss any blocking welcome / "What's New" / setup-prompt sheet that appeared on launch. Returns the app name and whether a modal was dismissed. Use this INSTEAD of `shell open -a X` when first opening an app you haven't driven before — saves the agent from the common failure mode of typing into a welcome modal instead of the actual UI. Looks for these dismiss buttons in priority order across any sheet or window of the frontmost app: Continue · Get Started · Skip · Later · Not Now · Got It · Maybe Later · Done · Cancel Generic — works for first-launch Apple apps (Reminders, Mail, Calendar, Photos, Maps, Music) and third-party apps that follow the same modal pattern.
03 SKILL.md 正文
app_open_clean — open + dismiss welcome modal
A common failure pattern when an LLM agent first drives a Mac app: launch the app → start typing or clicking → realize too late that a "What's New" or "Welcome" sheet was sitting on top of the real UI the whole time. The keystrokes go nowhere or hit the wrong target. The app looks unresponsive but is actually working fine; the modal is invisible to the AX-walk because it's a separate sheet.
This skill handles both phases in a single tool call:
open -a <app>— launches via Launch Servicesosascriptwalks the frontmost process's windows + sheets, clicks the highest-priority dismiss button it finds, repeats once for stacked welcome flows.
If the app has no modal (already dismissed, or never had one), the script exits clean and reports "no modal found" — completely safe to call on already-open apps.
When to use
- You're driving a built-in macOS app you haven't touched in this session: Reminders, Mail, Calendar, Photos, Maps, Music, etc.
- You just upgraded macOS — every app's "What's New" fires once.
- A third-party app you've never opened on this machine (Bear, Slack, Notion, etc.).
When NOT to use
- App is already running and you've already used it —
shell open -ais enough, no modal will appear. - The "modal" you want to keep — e.g. you opened Mail to use the Add
Account flow on purpose. (Use
shell open -a Maildirectly then.)
Examples
app_open_clean app=Reminders
→ opened: Reminders
dismissed: Continue → Got It
app_open_clean app=Calculator
→ opened: Calculator
dismissed: (no modal found)
Why a SKILL.md and not native
Pure shell + osascript. No Go state, no AX walking via kinax that
this skill doesn't already get from the standard ui tool. Sticks
to the "thin kernel + fat skill" thesis — apps come and go, modal
shapes evolve, this is exactly what forge should be writing.
Override / extend
If your installed app has a different dismiss button label not in
the priority list (e.g. "Begin", "OK, got it", "下一步"), edit this
SKILL.md and add it to dismissBtns. Or forge a sibling skill
named after the specific app.
04 同仓库更多 Skills
web
Universal web tool — fetches and interacts with web pages through real Chromium (Playwright). Renders JavaScript, follows redirects, handles cookies, bypasses many anti-scrape stubs that block plain `web_fetch`. Each call launches a fresh browser, executes the requested flow, closes. ~2-3s cold start; no persistent state. Use INSTEAD of `web_fetch` when: - Target is a JS-heavy SPA (prices via XHR, lazy content) - `web_fetch` returned an anti-scrape placeholder (Zhihu's "click here" stub, JD's chrome-only HTML) - You need to interact (click, fill input) before extracting Common patterns: fetch rendered text: url=X wait for content then read: url=X wait_for=".price" extract specific element: url=X selector=".product-list" click and read result: url=X click=".search-button" fill form, then read: url=X click="input[name=q]" type_text="kinclaw" fill + Enter (React forms): url=X click="input" type_text="hi" press_enter=true wait_for=".reply" screenshot the page: url=X screenshot=true (returns image:// marker) run JS and get result: url=X js="document.title" First-time setup (one-time per machine, ~500MB Chromium download): pip install playwright playwright install chromium
weather
Current conditions plus a three-day forecast (today / tomorrow / day after) for a place, in metric, from wttr.in. No API key. Use this for any weather question — including "明天" and "后天" — before reaching for web search.
tts
Synthesize speech from text and play it through the macOS speakers. Talks to a local LocalKin Service Audio Server (default :8001 / Kokoro). When `record` is running with audio=true, the spoken audio is captured into the recording — use this in place of `shell say` for high-quality multilingual narration in demo videos. Set the TTS_ENDPOINT env var to point at a different server.
translate
Translate text between languages using the system's translate command
summarize
Summarize a file's contents into key bullet points
stt
Transcribe an audio file (wav/mp3/mp4/m4a) into text via a local LocalKin Service Audio Server (default :8000 / SenseVoice). Pair with `record action=start mic=true` to turn a recorded mic track into text. Set STT_ENDPOINT env var to point at a different server.