DEPRECATED: Bridge SDK (moved into Adom Bridge)
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-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
.zipis a RELEASE, never a git file:*.zipis gitignored andrepo push --files X.zipreportsokbut 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 assertschrome.js+ the change are inside the zip before upload.node_modulesis excluded because ADnpm 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.json → version, 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 andsrc/bridge.jsonsorefresh_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/sizeMUST match the served asset orbridge_installrejects 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 at1.4.0while your last pkg sat at1.3.9makes a barepkg 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 (wikiadom/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 packincludes EVERYTHING by default → a fat tarball (all the hero PNGs +src/runtime). Fix: the heroes are gitignored (*.png) since they're already page assets, ANDpackage.jsonhas afilesallowlist. With both, the tarball drops to ~12 KB. (Pup's was 16 MB before the guards.)filesdirectory entries need a GLOB. Listing"skills"(bare dir) silently includes ZERO skill files. Use"skills/**"(and/or the explicit"skills/<name>/SKILL.md"). Alwaystar tzfto confirm your skills actually made it in — a missing skill = an empty Skills tab.pkg packhonors.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 thefilesallowlist for that.- A RELEASE shows up in
adom-wiki pkg infoas a row withtype:null(wiki UI conflation). The real pkg rows aretype:"app". Useadom-wiki release listfor true releases; don't think your pkg shipped just because a version appears inpkg info. - sha/size mismatch →
bridge_installrejects the manifest. Releases preserve the uploaded sha, so use therelease uploadresponse values verbatim and re-download to confirm. - The Skills tab +
skill_count+adom-wiki skills installcome from the GIT REPO, not the pkg. The wiki indexes everySKILL.mdin the page repo (root = main skill;<dir>/SKILL.md= sub-skills) —page.skillsis null; it's a repo scan. So a file namedSKILL.mdANYWHERE in the repo becomes an indexed, tab-listed,skills install-able skill. (This is separate frompkg install, which installs the pkg tarball governed by thefilesallowlist.) 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_countstays 1), not on the Skills tab, notskills install-able; - still in git → available via
adom-wiki repo clone(and the Files tab); - excluded from the pkg too (the
filesallowlist lists onlySKILL.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 1 —
curl -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 viaadom-wiki discover triggers <ref> --add ...ORpage.jsondiscovery_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, plusopen 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.
---
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 <bridge>/<prefix> 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)
```bash
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
```bash
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):
```python
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 install`s it on spawn (an
> 88 MB zip would exceed wiki limits).
### 3. Publish the zip as a Release (releases PRESERVE your sha)
```bash
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.json` → `version`, `url` (the release download URL), `sha256`,
`size` (from step 3 — **must match the served asset or `bridge_install` rejects it**):
```json
{ "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:
```bash
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
```bash
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)
```bash
# 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 **1** —
`curl -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:
```bash
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):
```bash
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.