Publish an IWSDK app to a public HTTPS origin so it can be installed as a PWA and packaged for the Meta Horizon Store. Use when deploying, hosting, or publishing the app, choosing a host, or when a file (web manifest, icons, .well-known/assetlinks.json) must reach an already-hosted site. Always asks first whether hosting already exists — recommends Vercel if not, and pauses with concrete upload steps if it does.
72
90%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Packaging a Quest APK reads the app over the network, not off disk:
bubblewrap fetches the web manifest and icons from the live origin, and the
Trusted Web Activity refuses to launch until Digital Asset Links are reachable
there too. So the origin — call it <DOMAIN> — comes first, and every later
step depends on files actually being served from it.
User request is in $ARGUMENTS.
Never assume. Ask the developer, up front, whether the app is already deployed — with a structured question tool (AskUserQuestion) if the harness has one, otherwise as a plain question. Do not deploy anything, do not pick a host, and do not run a deploy CLI until this is answered.
Is this app already deployed to a public HTTPS URL?
- Not deployed yet — recommend a host → Route A
- Already hosted / host already chosen (Netlify, Cloudflare Pages, GitHub Pages, S3+CloudFront, Firebase, own nginx/Apache server, internal CDN…) → Route B
- Deployed, but open to moving it → describe both, then let them pick
If they answer with a URL, treat it as Route B and use that URL as <DOMAIN>.
If they are unreachable and you must proceed autonomously, take Route A, and
mark the choice [ASSUMED] in whatever plan or report you are writing.
Recommend Vercel, and say why in one line: it detects Vite with no config,
serves dist/ over HTTPS with a stable public alias, keeps public/ dotfolders
like .well-known/ intact, and redeploys with one command — which matters
because asset links force a second publish later.
npm run build # → dist/
npx -y vercel@latest whoami # auth check
npx -y vercel@latest teams ls # find <team-slug>
npx -y vercel@latest deploy --prod --yes --scope <team-slug>Use the canonical alias (https://<project>.vercel.app) as <DOMAIN>, not
the hashed per-deploy URL — under team deployment protection the hashed URL
returns 401 and every downstream fetch fails. Full walkthrough, first-run login,
and the redeploy rule: references/vercel.md.
Then run the contract check.
The developer owns the host, so you do not publish — you prepare files and
stop. Every time something new has to reach <DOMAIN>, run the handoff below
rather than guessing at their pipeline.
Publishing to an existing host happens at least twice, and the second one is easy to forget:
| # | When | What must reach <DOMAIN> |
|---|---|---|
| 1 | after the manifest + icons exist | the whole built dist/ |
| 2 | after the signing keystore exists | dist/.well-known/assetlinks.json (rebuild first) |
A third happens for any later web-only fix — those need only a republish, never a new APK.
Run this at each row above. Keep it short and literal; the developer should be able to act without asking a follow-up question.
npm run build. Vite copies public/ — including
dotfolders like .well-known/ — verbatim into dist/.references/existing-hosts.md. If the host is
one you do not recognize, ask how they normally publish and adapt.!.Handoff message template:
Ready to publish. Please upload these to <DOMAIN>:
dist/manifest.webmanifest → https://<DOMAIN>/manifest.webmanifest
dist/icons/icon-192.png → https://<DOMAIN>/icons/icon-192.png
dist/icons/icon-512.png → https://<DOMAIN>/icons/icon-512.png
dist/icons/icon-512-maskable.png → https://<DOMAIN>/icons/icon-512-maskable.png
(or simply publish all of dist/ — these are already inside it)
On <host>, that is:
<the one command, or the exact dashboard click path>
Tell me when it is live and I will verify, then continue with packaging.Whichever route was taken, <DOMAIN> must satisfy all of this before
bubblewrap update runs. Check it yourself — do not take "it is deployed" as
proof.
| URL | Expected |
|---|---|
https://<DOMAIN>/ | 200, HTTPS, valid cert |
https://<DOMAIN>/manifest.webmanifest | 200, Content-Type: application/manifest+json |
https://<DOMAIN>/icons/icon-512.png | 200, image/png |
https://<DOMAIN>/.well-known/assetlinks.json | 200, application/json (after the keystore step) |
https://<DOMAIN>/android.keystore | 404 — the keystore must never be published |
for u in / /manifest.webmanifest /icons/icon-512.png /.well-known/assetlinks.json; do
printf '%s ' "$u"; curl -s -o /dev/null -w '%{http_code} %{content_type}\n' "https://<DOMAIN>$u"
done
curl -s -o /dev/null -w 'keystore %{http_code} (want 404)\n' "https://<DOMAIN>/android.keystore"Two failures are worth calling out because they look like host bugs and are not:
.well-known/ 404s while everything else works — the host is stripping
dotfolders. Fix per references/existing-hosts.md;
do not work around it by moving the file, the path is fixed by the TWA spec.text/plain — some hosts have no mapping for
.webmanifest. Add the MIME type, or serve it as manifest.json and update
the <link rel="manifest"> and webManifestUrl to match.If the app is served from https://<DOMAIN>/<path>/ rather than the origin
root, two things change and both break silently:
start_url and scope in the web manifest must be /<path>/, not /.assetlinks.json still has to sit at the origin root
(https://<DOMAIN>/.well-known/assetlinks.json) — a subpath copy is ignored.
If the developer does not control the origin root, they cannot ship a TWA from
that origin. Say so plainly and offer Route A as the alternative.base: './' is already set in the scaffolded vite.config.*, so the JS/CSS
bundles themselves are fine at any path — it is only these two that need care.
Once the APK exists, keep this distinction straight — it saves a Store round trip:
<DOMAIN>. The installed TWA picks it up on next launch.| File | Load when |
|---|---|
references/vercel.md | Route A — full Vercel deploy, auth, aliases, redeploys |
references/existing-hosts.md | Route B — per-host publish recipes and their gotchas |
Packaging the hosted app into a signed Quest APK is the iwsdk-pwa-packaging
skill; this skill only gets it online.
0778f51
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.