App manifest contract
An external mosaic app is a normal web app on its own origin. To be installable as a launcher tile, serve a manifest at /.well-known/mosaic.json — with CORS enabled so the launcher can fetch it — matching this JSON schema (v0.1):
{
"slug": "etch",
"name": "Etch",
"url": "https://etch.example.com",
"emoji": "🛰️",
"description": "Ambient GPS journal (bring your own server)"
}| Field | Req | Meaning |
|---|---|---|
slug | ✓ | lowercase kebab-case id, unique per user registry |
name | ✓ | tile display name |
url | ✓ | absolute URL the tile opens |
icon | square icon URL | |
emoji | fallback glyph when no icon | |
description | one-liner shown while installing | |
widget.endpoint | reserved: glance-widget JSON endpoint (spec coming) |
How installation works
- The user opens the launcher's Apps page (swipe left, or
/#apps) and pastes your app's URL. - Mosaic fetches the manifest, validates it, and adds a tile.
- The registry lives only in that user's localStorage — there is no server-side app directory and no review process.
The hard rule
Linked, never embedded. Mosaic will not iframe your app or import your code — the launcher origin holds users' OAuth tokens, so no third-party code runs there, ever. Your app gets its own origin, its own storage, its own permissions. Storage is entirely your concern (etch, for instance, talks to a server the user runs on their own tailnet — see Storage for the pattern and requirements).
Feeling native
- Adopt the design contract.
- Ship a PWA manifest so standalone installs look right.
- If users reach you from an HTTPS mosaic deploy, your app must be HTTPS too (mixed-content rules) — on a tailnet,
tailscale servegives you certificates.