name: bridge-publish-template user-invocable: false description: "TEMPLATE — the canonical, battle-tested recipe for publishing a new version of ANY Adom Desktop bridge to wiki.adom.inc, plus every gotcha hit live. Copy into your own bridge's dev-skills/, replace the / placeholders, and follow it. NOT for general users. Read before cutting a release: which artifact goes where (pkg=skills, release=bridge zip, repo=manifest+source), version-lockstep (kept above the AD bundled seed), the files allowlist + skills/** glob trap, keeping the tarball lean (NO zip / NO src / NO heroes), keeping dev/publish skills SOURCE-ONLY (not SKILL.md), deploying skills to .claude AND .codex, scrubbing retired-wiki host URLs, user-first discovery triggers, sha matching, and verify steps. Trigger words: publish bridge, ship bridge, release bridge, pkg publish, repo push, adom-wiki release, bridge manifest, bridge version bump, no zip in tarball, dev skill source only, scrub old wiki url, codex skills, discovery triggers, adom-desktop bridge publish template."

bridge-publish-template — shipping a new <bridge> bridge version

Template — copy into your bridge's own dev-skills/, replace the <bridge>/<prefix> placeholders, follow the steps.

This is the step-by-step ship recipe for a cloud-owned Adom Desktop bridge living at wiki.adom.inc/adom/adom-desktop-<bridge>-bridge, plus the traps that cost real time. Companion docs in your repo: a *-dev.md dev skill (architecture / ownership), a terse PUBLISHING.md, and CLAUDE.md (ownership boundary).

Placeholder legend — replace consistently throughout before you ship:

Placeholder Meaning Example (Puppeteer bridge)
<bridge> lowercase bridge id puppeteer
<Bridge Name> display name Puppeteer
<prefix>_ verb prefix browser_
adom-desktop-<bridge>-bridge wiki slug adom-desktop-puppeteer-bridge
adom-bridge-<bridge>-manifest.json streaming manifest filename adom-bridge-puppeteer-manifest.json
adom-bridge-<bridge>-v<version>.zip release zip filename adom-bridge-puppeteer-v1.1.1.zip
<your bridge's files> the runtime source files server.js, chrome.js, bridge.json
<your runtime> the language/runtime AD reconstructs node + node_modules

What goes WHERE — three artifacts, three homes (memorize this)

Artifact Home Command Carries
bridge runtime .zip a Release asset adom-wiki release upload src/ at zip-root (<your bridge's files> — the thing AD runs).
streaming manifest JSON the git repo adom-wiki repo push points at the release zip URL + its sha256/size
container skills tarball a Package adom-wiki pkg publish SKILL.md + skills/* (the Claude/Codex skills). NO runtime.

The .zip is a RELEASE, never a git file: *.zip is gitignored and repo push --files X.zip reports ok but silently skips it (the URL then 404s). Binaries → release upload.

Auth (once per container)

export ADOM_WIKI_TOKEN=$(cat /var/run/adom/api-key 2>/dev/null)   # container default; or session.json's login session_token
adom-wiki whoami    # MUST show a real user (e.g. [email protected]). Strict-auth rejects the shared "Developer" token.

ADOM_WIKI_TOKEN is the user's login session_token — the container default lives at /var/run/adom/api-key; otherwise pull it from ~/.adom/session.json. Every mutation needs a real --changelog / -m (≥10 chars, ≥2 words) or the server 400s.

The recipe

1. Bump version IN LOCKSTEP, and keep it > the AD bundled seed

printf '1.1.1' > src/BRIDGE_VERSION
sed -i 's/"version": "1.1.0"/"version": "1.1.1"/' src/bridge.json    # bridge runtime
sed -i 's/"version": "1.1.0"/"version": "1.1.1"/' package.json       # adompkg descriptor (the pkg)

src/BRIDGE_VERSION and src/bridge.json MUST match (AD uses BRIDGE_VERSION to detect a stale running process). Keep the number above the seed in adom-desktop/plugins/<bridge> so cache-over-bundled wins.

2. Build the bridge zip (source-only, src/ at zip ROOT — no top-level dir)

zip may be absent → Python. Your <your runtime> deps (e.g. node_modules) are NEVER included (AD reconstructs them on spawn; the seed ships them; a fat zip would blow wiki limits):

import zipfile, os, hashlib
root, out = "src", "adom-bridge-<bridge>-v1.1.1.zip"
with zipfile.ZipFile(out, "w", zipfile.ZIP_DEFLATED) as z:
    for dp, dirs, files in os.walk(root):
        for skip in ("node_modules","screenshots","profiles"):   # your runtime's heavy/generated dirs
            if skip in dirs: dirs.remove(skip)
        for f in files: z.write(os.path.join(dp,f), os.path.relpath(os.path.join(dp,f), root))
print("sha256:", hashlib.sha256(open(out,"rb").read()).hexdigest(), "size:", os.path.getsize(out))
# SANITY: assert your changed file(s) are inside before shipping.

Concrete pup example (so the commands aren't abstract): the Puppeteer bridge skips node_modules/screenshots/profiles, and its sanity check asserts chrome.js + the change are inside the zip before upload. node_modules is excluded because AD npm installs it on spawn (an 88 MB zip would exceed wiki limits).

3. Publish the zip as a Release (releases PRESERVE your sha)

adom-wiki release create adom/adom-desktop-<bridge>-bridge 1.1.1 --title "..." --changelog "<≥2 words>"
adom-wiki release upload adom/adom-desktop-<bridge>-bridge 1.1.1 adom-bridge-<bridge>-v1.1.1.zip --json
# the response's assets[].sha256/size are what the manifest MUST carry. Then VERIFY the PUBLIC url:
curl -sL https://wiki.adom.inc/download/adom/adom-desktop-<bridge>-bridge/1.1.1/adom-bridge-<bridge>-v1.1.1.zip | sha256sum

4. Point the manifest at the release + push it (git repo)

Edit adom-bridge-<bridge>-manifest.jsonversion, url (the release download URL), sha256, size (from step 3 — must match the served asset or bridge_install rejects it):

{ "manifest_version": 1, "name": "<bridge>", "version": "1.1.1",
  "url": "https://wiki.adom.inc/download/adom/adom-desktop-<bridge>-bridge/1.1.1/adom-bridge-<bridge>-v1.1.1.zip",
  "sha256": "<the release asset's sha256>", "size": <bytes>,
  "verbPrefixes": ["<prefix>_"],
  "healthEndpoint": "/status", "statusVerb": "<prefix>_readiness",
  "updateManifestUrl": "https://wiki.adom.inc/api/v1/pages/adom-desktop-<bridge>-bridge/files/adom-bridge-<bridge>-manifest.json",
  "released_at": "<UTC ISO8601>" }

Declare updateManifestUrl (the full URL of THIS manifest on your own page) in both the manifest and src/bridge.json so refresh_bridges / the auto-poll reach YOUR page instead of the legacy AD-owned convention. Then push:

adom-wiki repo push adom/adom-desktop-<bridge>-bridge \
  --files adom-bridge-<bridge>-manifest.json src/bridge.json src/BRIDGE_VERSION <your bridge's files> SKILL.md \
  -m "v1.1.1: <what changed>"

sha256/size MUST match the served asset or bridge_install rejects it. Re-download to confirm: curl -sL <download_url> | sha256sum.

5. Publish the container skills as a pkg — keep it LEAN, and MIND THE TRAPS

adom-wiki pkg pack            # ALWAYS pack + inspect BEFORE publish
tar tzf *.tgz                 # confirm: SKILL.md + skills/*/SKILL.md + install.sh, and NOTHING heavy
adom-wiki pkg publish --org adom --version 1.1.1
adom-wiki pkg notes adom/adom-desktop-<bridge>[email protected] -m "Container skills: <what changed>"

The pkg description lives in the root package.json description — keep it explicit that this is container-side skills only; the bridge runtime is the Release zip + bundled in Adom Desktop.

Traps hit live (don't relearn these)

  • ⛔ A RELEASE and its PKG must ship TOGETHER. Never leave a release as your MAX version row with no matching pkg tarball. Both pillars share ONE version list, and the pkg resolver picks the max satisfying row and then fails if that row has no tarball, rather than skipping it or honoring distTags.latest. So publishing a release at 1.4.0 while your last pkg sat at 1.3.9 makes a bare pkg install adom/<your-bridge> and every constraint install (@^1.3.0, @^1.4.0) return 404, breaking every consumer at once. It can look fine for months, purely because your previous max row happened to exist as both. AD core hit this live (wiki adom/wiki #22) and it transitively broke unrelated installs. If you cannot publish both in one session, hold the release. Do NOT relabel an older tarball to close the gap: a stale skill pkg silently omits the very verbs the new release added, which is worse than the 404 because nothing reports it. Interim unblock for a stuck consumer: pin an explicit version (adom/<your-bridge>@1.3.9), which skips the constraint resolver.
  • pkg pack includes EVERYTHING by default → a fat tarball (all the hero PNGs + src/ runtime). Fix: the heroes are gitignored (*.png) since they're already page assets, AND package.json has a files allowlist. With both, the tarball drops to ~12 KB. (Pup's was 16 MB before the guards.)
  • files directory entries need a GLOB. Listing "skills" (bare dir) silently includes ZERO skill files. Use "skills/**" (and/or the explicit "skills/<name>/SKILL.md"). Always tar tzf to confirm your skills actually made it in — a missing skill = an empty Skills tab.
  • pkg pack honors .gitignore, not a separate npmignore. So you can't gitignore something you need in git (e.g. src/) to drop it from the pkg — use the files allowlist for that.
  • A RELEASE shows up in adom-wiki pkg info as a row with type:null (wiki UI conflation). The real pkg rows are type:"app". Use adom-wiki release list for true releases; don't think your pkg shipped just because a version appears in pkg info.
  • sha/size mismatch → bridge_install rejects the manifest. Releases preserve the uploaded sha, so use the release upload response values verbatim and re-download to confirm.
  • The Skills tab + skill_count + adom-wiki skills install come from the GIT REPO, not the pkg. The wiki indexes every SKILL.md in the page repo (root = main skill; <dir>/SKILL.md = sub-skills) — page.skills is null; it's a repo scan. So a file named SKILL.md ANYWHERE in the repo becomes an indexed, tab-listed, skills install-able skill. (This is separate from pkg install, which installs the pkg tarball governed by the files allowlist.) Corollary → see "Keep dev/publish skills source-only".

Verify (every ship)

# manifest serves at the updateManifestUrl path:
curl -s https://wiki.adom.inc/api/v1/pages/adom-desktop-<bridge>-bridge/files/adom-bridge-<bridge>-manifest.json | jq .sha256
# anon-fetch the PUBLIC release zip URL and confirm the sha matches the manifest (curl 200 is NOT enough):
curl -sL https://wiki.adom.inc/download/adom/adom-desktop-<bridge>-bridge/1.1.1/adom-bridge-<bridge>-v1.1.1.zip | sha256sum
# live install + new verbs on a real desktop (multi-desktop → --target; `adom-desktop targets` lists them):
adom-desktop --target <name> bridge_install '{"manifestUrl":".../files/adom-bridge-<bridge>-manifest.json","force":true}'
adom-desktop --target <name> <prefix>_readiness '{}'
# bridge_list shows the new version + skillPkg; bridge_check_updates reaches your page; sync_skills pulls the user skill:
adom-desktop --target <name> bridge_list '{}'            # confirm version + skillPkg (adom/adom-desktop-<bridge>-bridge)
adom-desktop --target <name> bridge_check_updates '{}'   # wikiHosted:true, latest = your new version
adom-desktop --target <name> sync_skills '{}'            # installs the user skill pkg into the container
# render the page in pup + READ the screenshot. Confirm version + Skills tab.

Server-only change → AD reaps + respawns the bridge from the new cache on the next <prefix>_* call.

Keep dev/publish skills SOURCE-ONLY (not on the Skills tab, not installed)

Everyday users should get ONLY the <bridge> user skill — not the dev/publish skills. But the wiki indexes every SKILL.md in the repo (above), so a dev skill named SKILL.md would show on the Skills tab AND install via skills install. The fix: keep dev/publish skills as source-only docs that are NOT named SKILL.md — they live in dev-skills/ as <bridge>-bridge-dev.md / <bridge>-bridge-publish.md. Then they are:

  • not indexed (skill_count stays 1), not on the Skills tab, not skills install-able;
  • still in git → available via adom-wiki repo clone (and the Files tab);
  • excluded from the pkg too (the files allowlist lists only SKILL.md + skills/**).

dev-skills/README.md tells a developer how to load one as a live skill (copy it to ~/.claude/skills/<name>/SKILL.md). Verify after publish: skill_count should be 1curl -s https://wiki.adom.inc/api/pages/adom/adom-desktop-<bridge>-bridge | jq '.page.skill_count'.

Keep the pkg tarball LEAN — NO zip, NO src/, NO heroes

The pkg tarball must be the <bridge> user skill ONLY — never the bridge runtime zip, src/, or hero PNGs. Guards: the package.json files allowlist (SKILL.md, skills/**, install.sh, uninstall.sh, README.md, package.json) plus .gitignore (*.zip, *.png, *.bundle, *.tgz, the old *-source.tar.gz). ALWAYS adom-wiki pkg pack then tar tzf *.tgz and confirm there is no *.zip, no src/, no *.png. A lean tarball is ~10 KB; if it's megabytes, something heavy leaked in (it was 16 MB before the guards). rm -f *.tgz after inspecting.

Skills install to BOTH .claude AND .codex

install.sh deploys the user skill into both ~/.claude/skills/ and ~/.codex/skills/ (Codex only if ~/.codex exists); uninstall.sh removes from both. Codex is a real second agent skills home now — don't ship an install.sh that only does .claude.

Scrub retired-wiki URLs (the #1 fork/extract gotcha)

The only wiki host is wiki.adom.inc. Any wiki-*.adom.cloud host is RETIRED — as are the /static/apps/... and /wiki/apps/... path formats. When you fork/extract a page, the inherited README.md and the page.json readme body carry OLD URLs (this bit pup live — a dead static/apps zip link). Before every publish:

grep -rnI 'adom\.cloud\|/static/apps\|/wiki/apps' . --exclude-dir=node_modules

Fix every hit (README + the page.json readme body are the usual culprits), then VERIFY the live entity (not just local):

curl -s https://wiki.adom.inc/api/pages/adom/adom-desktop-<bridge>-bridge | grep -c '\.adom\.cloud'   # want 0

Also repo rm any stale source-mirror artifacts left on the page (old *-source.tar.gz / *.bundle). (https://adom.inc/fonts/... is fine — that's the brand font CDN, not a wiki host.)

Canonical wiki.adom.inc URL formats

  • Page: https://wiki.adom.inc/adom/<slug>
  • File (served, anon): https://wiki.adom.inc/api/v1/pages/<slug>/files/<name>
  • Release download: https://wiki.adom.inc/download/adom/<slug>/<ver>/<file>
  • Sibling pages: /adom/adom-desktop-bridges, /adom/adom-desktop-kicad-bridge, /adom/adom-desktop-fusion-bridge, /adom/adom-desktop

Discovery triggers — lead with everyday USER phrases

Lead discovery_triggers with everyday phrases, not dev jargon — the single most important is the bare bridge name users actually say. The wiki auto-generates the discover snippet from discovery_triggers

  • discovery_pitch (there is no separate "upload a snippet" — those two fields ARE the snippet). Set them via adom-wiki discover triggers <ref> --add ... OR page.json discovery_triggers/discovery_pitch
  • push. Verify: adom-wiki discover preview "<a natural user phrase for your bridge>" should rank this page #1.

Concrete pup example: the most important trigger is the bare word pup, plus open in pup, open my app in pup, screenshot the page, record a browser window. adom-wiki discover preview "open my app in pup" must rank the Puppeteer page #1.