---
name: bridge-user-skill-template
user-invocable: true
description: "TEMPLATE for an Adom Desktop bridge's CONSUMER skill — copy it, then replace <bridge>/<Bridge Name>/<prefix> and the verb glosses. It teaches a cloud Claude/Codex AI how to DRIVE <Bridge Name> on the user's desktop via the adom-desktop CLI: <one-line value prop — what the bridge controls and why>. Includes a FIRST-USE / COLD-START warm-up section so the AI doesn't panic on a fresh machine. Keep a trigger-words line like this one so the skill activates. Trigger words: <bridge>, <Bridge Name>, <prefix>_<verb1>, <prefix>_<verb2>, <prefix>_readiness, <prefix>_prewarm, <2-3 plain-English phrases a user would say, e.g. 'open in <bridge>', '<bridge> screenshot'>."
---

> Template — copy into your bridge's pkg as `skills/<bridge>/SKILL.md`, replace `<bridge>`/`<prefix>`.

# <Bridge Name> — <one-line capability summary> (with first-use warm-up)

Drive <Bridge Name> on the user's desktop from the cloud via the `adom-desktop` CLI. All verbs are
Bash commands (NOT MCP tools):

```bash
adom-desktop <command> '<json_args>'
```

## ⭐ FIRST-TIME / COLD-START — read this BEFORE you panic that "<prefix>_<verb> did nothing"

On a brand-new machine (e.g. the user just installed the app that bundles Adom Desktop),
**something <Bridge Name> needs may NOT be pre-installed by the installer** — a runtime, a large
dependency, an external app, or a one-time download. The bridge handles this gracefully — your job is
to **read the structured response and follow it, not to give up.**

When you run a `<prefix>_<verb>` on a cold machine, one of these happens — handle each:

| Response | What it means | What you do |
|---|---|---|
| `errorCode: "<dependency>_not_found"` | A required runtime/dependency isn't installed (the bridge can't start). | Run the bridge's documented install verb (e.g. `adom-desktop <prefix>_install_<dep> '{}'`), wait for it, then retry the original verb. |
| `errorCode: "<resource>_installing"` (`installing:true`) | **A needed resource is missing; the bridge is auto-downloading/installing it now (one time).** This is EXPECTED on a fresh machine — NOT a failure. | **Poll `<prefix>_readiness` until `ready:true`**, THEN re-issue the exact same verb. You do NOT install anything yourself. Do NOT report failure to the user. |
| `errorCode: "<resource>_install_failed"` / `<resource>_download_failed` | The download/install itself failed. | Read `readiness.lastError`. It's usually no network / a proxy / low disk — NOT your fault. Retry `<prefix>_prewarm`; if it persists, surface `lastError` to the user, and use any documented fallback mode. |
| `ok:true` / a real session | Everything was already warm. | Proceed normally. |

### The clean cold-start recipe

```bash
# 1) (optional but nice) Warm the bridge WITHOUT doing real work first:
adom-desktop <prefix>_prewarm '{}'             # returns fast; kicks off any first-use install

# 2) Poll readiness until ready (the bridge sets itself up):
adom-desktop <prefix>_readiness '{}'           # → {ready:false, installing:true, installProgressPct:42, ...}
#    ...wait a few seconds, poll again until → {ready:true, ...}

# 3) Now do the real work — it's instant:
adom-desktop <prefix>_<verb> '{"sessionId":"<id>", ...}'
```

`<prefix>_prewarm` and `<prefix>_readiness` are the two cold-start verbs. `<prefix>_prewarm '{"wait":true}'`
blocks until setup finishes instead of returning immediately. **Always surface a verb's `_hint`
field verbatim to the user when something isn't ready** — it tells you (and them) exactly what's happening.

> **Concrete example (the Puppeteer/pup bridge):** on a fresh PC, `browser_open_window` returns
> `errorCode: "chrome_for_testing_installing"` (`installing:true`) because Chrome for Testing (~150 MB)
> is auto-downloading. That is NOT a failure — you poll `browser_readiness` until `{ready:true}`, then
> re-issue the same `browser_open_window`. Before the bridge handled this, a cold PC failed with a
> generic "Failed to launch after 3 attempts" and the AI flailed. Don't reintroduce the panic; read
> the structured response and follow the table.

## How to Run Commands

```bash
adom-desktop <prefix>_<verb>      '{"sessionId":"myjob", ...}'   # do a unit of work
adom-desktop <prefix>_screenshot  '{"sessionId":"myjob"}'        # capture current state (lossless PNG)
adom-desktop <prefix>_status      '{}'                           # list sessions + readiness
```

**These are Bash commands, not MCP tools.** If your verbs are session-scoped, always pass `sessionId` —
`'{}'` targets the *active* session, which may not be the one you mean.

## Background by default — don't disrupt the user

**<Bridge Name> is the AI's workspace, not the user's. Keep its windows/output OUT of the user's way unless they asked to watch.**

- After opening/driving something for automation (a screenshot, a scrape, a debug loop), send it to the
  back / leave it un-focused so it doesn't sit on top of what the user is doing (e.g. a
  `<prefix>_lower_os_window` or equivalent).
- **Never** force your window to the foreground unless the user must SEE it — a recording, a demo, or a
  finished result you're explicitly showing them.
- Use a **non-intrusive nudge** (flash the taskbar via a `<prefix>_alert_window`-style verb, or just
  report in chat) for "it's ready / done" instead of stealing focus.
- For long-running output the user WILL look at, a dedicated window is fine — but still don't re-raise
  it on every update; nudge instead of grabbing focus.

```bash
adom-desktop <prefix>_<verb>          '{"sessionId":"job", ...}'
adom-desktop <prefix>_lower_os_window '{"sessionId":"job"}'   # get it off the user's screen; keep driving headlessly
# ...do work as needed (works while lowered/backgrounded)...
adom-desktop <prefix>_alert_window    '{"sessionId":"job"}'   # non-intrusive "done" when you want their attention
```

## Core verbs

| Command | Description | Key args |
|---|---|---|
| `<prefix>_readiness` | Cold-start probe: is the bridge set up / still installing? | none |
| `<prefix>_prewarm` | Do first-use setup WITHOUT starting real work | `wait` (optional bool) |
| `<prefix>_open_window` *(or your "start a session" verb)* | Spawn a new session/window | `sessionId`, `profile`, ... |
| `<prefix>_<do-work>` | The bridge's primary action verb(s) | `sessionId`, ... |
| `<prefix>_screenshot` | Capture current state (lossless PNG) | `sessionId`, `fullPage?` |
| `<prefix>_status` | All sessions + readiness | none |
| `<prefix>_lower_os_window` | Send the window to the back (keep it off the user's screen) | `sessionId` |
| `<prefix>_raise_os_window` / `<prefix>_focus_window` | Bring to foreground (use sparingly — only to show the user) | `sessionId` |
| `<prefix>_alert_window` | Flash the taskbar (non-intrusive attention) | `sessionId` |
| `<prefix>_close_window` | Close one session + its window (destructive) | `sessionId` |
| `<prefix>_close` | Close ALL sessions | none |

Run `adom-desktop <prefix>_describe '{}'` for the full machine-readable verb catalog.

## Sessions & persistence (if your bridge has sessions)

If one session = one long-lived context (a window, a connection, a document), say so here, and tell the
AI **how to reuse instead of re-open**:

- New context entirely → `<prefix>_open_window` (or your start verb).
- Reuse an existing one → drive it directly (a `<prefix>_navigate`/equivalent), don't open a second.

**Run `<prefix>_status '{}'` before opening a new session** at the start of a conversation (especially
after a context compaction) — if a session already matches what you're about to do, reuse it. Opening a
duplicate leaves the user staring at two identical windows. Pick a **stable `profile`/identifier across
runs** so any persisted state (logins, cookies, caches) survives — the user sets up once, reuses for
months.

## Verify what you did — `ok:true` is not enough

Many start/action verbs return `ok:true` as soon as the operation *begins*, not when it *finished* /
rendered. Sanity-check with the cheapest signal: a `<prefix>_eval`/read verb that reflects real state
(fastest), or a `<prefix>_screenshot` when a value isn't discriminating. Don't report success to the
user on `ok:true` alone for anything that can silently land on an error/empty state.

## Key rules

- **Always pass `sessionId`** for session-scoped verbs. Never `'{}'` when you mean a specific session.
- **It's `adom-desktop <prefix>_<cmd> <json>`** — there is no top-level `<bridge>` subcommand.
- **Surface `_hint` verbatim** whenever a verb reports it isn't ready or failed — it's written for both
  you and the user.
- **Reuse, don't reflexively close+reopen** — persisted state is keyed by `profile`/identifier; prefer a
  reload/navigate over a destroy+recreate.
- **Never broadly kill the underlying app/process** — use the bridge's per-session close
  (`<prefix>_close_window`) so you don't nuke unrelated work.
- **Document any per-verb gotchas** here (escaping rules, arg quirks, timeouts) — e.g. pup's
  "no semicolons in `browser_eval` — use the comma operator or an IIFE."

---
