← Commit history

Add shipping-a-bridge skill: the current release + UPDATE flow (artifact not git Files; .zip blocked so .bin; canonical owner-scoped URL; bridge_install records manifestUrl for auto-update [AD 1.9.26+]; refresh_bridges self-reaps [1.9.27+]; declare new verbs in bridge.json verbs[])

John Lauer ·1c430fb163 ·4mo ago ·parent 6803481
1 file changed +87
skills/shipping-a-bridge/SKILL.mdadded+87
@@ -0,0 +1,87 @@+---+name: shipping-a-bridge+description: How to ship + UPDATE a third-party Adom Desktop bridge so AD actually picks it up. The cardinal fact authors get wrong: AD reads ONLY the bridge RELEASE ARTIFACT (a manifest + a zip), NEVER the git Files tab of your wiki page - so pushing your source to the repo updates what humans browse but does NOT reach AD. Covers building the manifest + versioned zip (files at zip root), the wiki .zip-upload trap (host the bytes as .bin), the canonical owner-scoped file URL (not the legacy /api/v1 alias), bridge_install (first time - records the manifest URL for auto-update, AD 1.9.26+) vs refresh_bridges (after; no manual kill on AD 1.9.27+), verifying with bridge_check_updates, and the rule that a new verb must be added to bridge.json verbs[] (and to your describe verb) or AD won't route it. Read when cutting a new bridge version, adding a verb, or when "AD is still running the old bridge". Companion to the bridge SDK guide (bridge.json schema + hello-python/hello-rust templates).+---+Companion to the **adom-desktop-bridges** SDK guide (bridge.json schema, kind:python/node/exe, the hello-python / hello-rust templates, `scripts/release-bridge.sh`). This page is the **release + update** flow and the traps.++# Shipping a bridge update (so adom-desktop picks it up)++Your bridge runs on the user's machine, spawned by AD from its writable **`bridges-cache`**. Updating it+is NOT a normal git push.++## ⛔ The cardinal fact: AD reads the RELEASE ARTIFACT, not your git Files+Your wiki page has two independent layers (same split as a README vs a package registry):+- **Git Files** (`adom-wiki repo push`) = what humans browse. **AD never reads this for bridge code.**+- **The release artifact** = a `<bridge>-bridge-manifest.json` (version + zip url + sha256) plus a+  **versioned zip**. This is the ONLY thing AD pulls.++So pushing your `server.js` to the repo changes nothing for AD. You must publish a new artifact and bump+the version.++## The artifact+- `<bridge>-bridge-manifest.json` = `{ "manifest_version":1, "version", "url", "sha256", "size", "released_at" }`.+- A zip whose ROOT contains `bridge.json` + your server file(s) (no top-level folder). **AD requires+  `bridge.json` at the zip root.** The easiest path is `scripts/release-bridge.sh <name>` (it builds the+  zip, sha256s it, writes the manifest). The manual equivalent:+  ```python+  import zipfile,hashlib,os+  out="/tmp/<bridge>-bridge-v<ver>.zip"+  with zipfile.ZipFile(out,"w",zipfile.ZIP_DEFLATED) as z:+      for f in ["bridge.json","server.js","package.json","BRIDGE_VERSION"]:   # your files, at ROOT+          z.write(f, arcname=os.path.basename(f))+  raw=open(out,"rb").read(); sha=hashlib.sha256(raw).hexdigest(); size=len(raw)+  ```+  (Note: in the Adom cloud container there is **no `zip` binary** - use Python `zipfile` as above.)++## ⛔ Trap: the wiki silently rejects `.zip` uploads+`POST .../files` with a `.zip` returns `{ok:true, commit:null}` but the file **never lands** (a `.png`+commits fine through the same path). So host the zip **bytes** under a **`.bin`** name+(`<bridge>-bridge-v<ver>.bin`) and point the manifest `url` at that. AD just HTTP-GETs the `url` and+unzips the bytes - the extension is cosmetic. (`adom-wiki repo push` also drops binaries except PNG; push+the `.bin` with `adom-wiki api -X POST .../files` as base64, and the manifest + source as text.)++## ⛔ Use the CANONICAL file URL (not the legacy alias)+Give AD the **owner-scoped, no-`/v1`** route:+```+https://wiki.adom.inc/api/pages/<owner>/<slug>/files/<bridge>-bridge-manifest.json+```+The `/api/v1/pages/<slug>/...` form is a legacy slug-only alias that still resolves but is fragile (breaks+on fork / when v1 retires). Older docs show the `/api/v1/` form; prefer the canonical one.++## Bump, build, publish+1. **Bump the version in every place your runtime + manifest read it** - typically `bridge.json` `version`,+   `BRIDGE_VERSION`, and your `package.json` `version`. A half-bump = AD sees no update, or a mismatched+   runtime version string.+2. Build the zip (root layout), compute `sha256` + `size`, write the manifest with `url:"<...>.bin"`.+3. Upload the `.bin` (base64) + push the manifest + source.+4. **Verify the artifact is live + intact** (AD sha256-checks on download): GET the `.bin`, confirm bytes+   == `size` and `sha256sum` == the manifest `sha256`.++## Make AD pick it up+- **First time on a machine:** `adom-desktop bridge_install '{"manifestUrl":"<canonical manifest url>"}'`.+  Downloads + sha-verifies + extracts into `bridges-cache`, AND **persists the manifest URL** so the bridge+  auto-updates from its own page. (AD **1.9.26+** tracks per-bridge manifest URLs - this is what lets a+  community bridge on its OWN wiki page auto-refresh, not just the bundled ones.)+- **Every update after that:** `adom-desktop refresh_bridges '{"name":"<bridge>"}'` (or AD's on-launch ++  4-hourly auto-sync). **AD 1.9.27+ auto-reaps the running process and respawns on the new code - NO manual+  `bridge_kill`.** Result: `action:"updated", from, to`. The running bridge respawns on the next verb call.++## Verify the update landed+- `adom-desktop bridge_check_updates` -> your bridge shows `current` == new version, `wikiHosted:true`,+  `updateAvailable:false`. (If `wikiHosted:false`/`latest:null`, AD has no tracked manifest URL - re-run+  `bridge_install` from the canonical URL once to register it.)+- Call one of your verbs (or your `<prefix>_describe` if you have one) to confirm the new code is running.++## Adding a verb? Update routing (and docs)+- **`bridge.json` `verbs[]`** - AD ROUTES a verb to your bridge only if it is declared here. Miss this and+  the verb 404s no matter what your server does.+- If you expose a **`<prefix>_describe`** verb (AD 1.9.23+ renders it in the GUI Verbs tab), add the new+  verb's schema there too, so it shows up with input/output docs + the inline runner.++## Mental model + the traps, in one line each+- **Two layers:** git Files = humans; release artifact = AD. A `repo push` is NOT shipping.+- **`.zip` is silently blocked** on the wiki API - host as `.bin`.+- **No `zip` binary** in the cloud container - Python `zipfile`, files at the zip root.+- **Canonical owner-scoped URL** for the manifest, not `/api/v1/<slug>`.+- **Bump every version file** together.+- **`refresh_bridges` self-reaps** (AD 1.9.27+) - re-running `bridge_install` per update is no longer needed.