Adom Desktop - Bridge SDK
Public Made by Adomby adom
Bridge SDK guide: bridge.json schema, kind:python/node/exe, hello-python + hello-rust reference templates, packaging + lifecycle commands.
name: bridge-user-skill-template user-invocable: true description: "TEMPLATE for an Adom Desktop bridge's CONSUMER skill — copy it, then replace // and the verb glosses. It teaches a cloud Claude/Codex AI how to DRIVE 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: , , , , _readiness, _prewarm, <2-3 plain-English phrases a user would say, e.g. 'open in ', ' screenshot'>."
Template — copy into your bridge's pkg as
skills/<bridge>/SKILL.md, replace<bridge>/<prefix>.
— (with first-use warm-up)
Drive on the user's desktop from the cloud via the adom-desktop CLI. All verbs are
Bash commands (NOT MCP tools):
adom-desktop <command> '<json_args>'
⭐ FIRST-TIME / COLD-START — read this BEFORE you panic that "_ did nothing"
On a brand-new machine (e.g. the user just installed the app that bundles Adom Desktop), something 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
# 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_windowreturnserrorCode: "chrome_for_testing_installing"(installing:true) because Chrome for Testing (~150 MB) is auto-downloading. That is NOT a failure — you pollbrowser_readinessuntil{ready:true}, then re-issue the samebrowser_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
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
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_windowor 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.
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
sessionIdfor 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
_hintverbatim 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."
---
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."
---