# Handoff to Bridge: expose ALL AD verbs to bridges via the direct-API

**From:** pup (pup-bridge)
**TL;DR:** A bridge should be able to call **any** AD verb the CLI can, through the
loopback direct-API (`127.0.0.1:47200`). Today it can only reach a **subset**
(`desktop_*` + other bridges' verbs). That's why pup can't fire `notify_user` to walk a
user through a Chrome UAC — but the fix should be general, not a one-off for notify.

## The two directions (so we're precise)

- **Inbound (AD → bridge):** AD routes verbs to a bridge by its declared prefixes
  (`pup_*` for pup). Works fine; not the issue.
- **Outbound (bridge → AD):** a bridge's only callback channel is the direct-API. AD's own
  `GET /commands` defines "reachable verbs" for a bridge as **`desktop_*` + `app:"dynamic"`
  bridge verbs only.** Top-level/lifecycle verbs are absent. So a bridge has a *partial*
  view of AD, not the full CLI surface.

## Evidence (AD 1.9.79, ADOMBASELINE)

`POST 127.0.0.1:47200/command`:

| body | result |
|---|---|
| `{app:"desktop", command:"notify_user"}` | `"Unknown desktop command: notify_user"` |
| `{app:"core"\|"adom"\|"cli", command:"notify_user"}` | `"Unknown app"` |
| `{app:"dynamic", command:"notify_user"}` | `"no installed bridge claims this prefix"` |
| `{command:"notify_user"}` | HTTP 400 |

`GET /commands` returns `{ desktop:[…desktop_* verbs…], bridges:[…], cliRequired:[…] }` —
no `notify_user`, `notify_response`, `ping`, `targets`, `server_*`, `bridge_*`, `hd_*`,
`updater_*`. Any bridge that needs one of those hits the same wall pup did.

## The ask — make the full verb set reachable by bridges

**1. Route every dispatchable verb through the direct-API**, not just `desktop_*`. A bridge
calling `POST /command {command:"<any verb>", args:{…}}` should hit the same dispatcher the
CLI/WS path uses and get the same JSON back (incl. `_hint`/`errorCode`/`statusVerb`). List
the full set in `GET /commands` so bridges can capability-probe (pup already does this and
will light up automatically).

**2. The `cliRequired` verbs** (`shell_execute`, `run_script`, `pull_file`, `send_files`,
`hd_send_files`) need the CLI's streaming/approval flow — so "all verbs" doesn't mean
"bypass approval." Keep their gates: make them **reachable** but still run the approval /
streaming path (or return a precise "call the streaming variant" error), rather than a bare
404. Don't silently drop them from a bridge's reach.

**3. Preserve the security posture, deliberately.** The direct-API is loopback-only, but
exposing the full surface (incl. `shell_execute`) to any local process is a real widening.
Recommended: AD hands each bridge a **spawn-time capability token** (env var) that the
direct-API requires for the sensitive/`cliRequired` verbs, so AD can attribute and authorize
bridge calls — and the per-verb approval prompts still fire. Bridges are AD-spawned, so AD
can mint the token cleanly.

**4. Cross-AD addressing (the attended-device problem).** A bridge reaches only its *local*
AD, but the user may be at a *different* connected AD (pup runs on a hypervm; the user is on
their laptop). Honor a **`target`** arg on direct-API calls — `"attended" | "<clientName>" |
"all"` — mirroring the CLI's global `--target`, so a bridge can route a verb (a
`notify_user`, a screenshot, anything) to the right box. `"attended"` = the AD the user is
present at (most-recently-focused / input-active). This makes the whole fleet addressable
from a bridge, and specifically lets pup ping the user wherever they actually are while the
UAC stays on the box that needs it.

## Why general, not per-verb

pup's immediate need is `notify_user` + `notify_response` (walk the user through a Chrome
UAC without an AI turn). But the kicad/fusion/native-browser bridges — and every future one
— will each want *some* verb outside the `desktop_*` slice (`notify_user`, `targets`,
`updater_*`, `bridge_list`…). Exposing the whole surface once removes the wall for all of
them. If you want to stage it: **(1) all non-`cliRequired` verbs + `target`** unblocks pup
today; **(2) `cliRequired` behind the capability token** follows.

## pup is already ready

pup probes `GET /commands` for `notify_user` and caches the result
(`readiness.chromeStableNotifyChannel`). The moment the verb appears, pup's notify-first
UAC flow activates with **zero pup release** for the local case. Cross-AD `target` is a
tiny pup follow-up once the arg is finalized. Full context:
`adom/pup-bridge` repo.
