Install the cockpit as a PWA¶
Install the cockpit served by agentctl top --web --gateway as a standalone app on a phone
or a laptop: a home-screen icon and its own window, without an address bar.
Installing changes the framing. Behind it every surface is the same live connection to the host that the browser tab had, so the app wants the network exactly as the tab did — see Behaviour once installed for offline, upgrades and notifications.
Requirements¶
| Requirement | Not installable when |
|---|---|
| HTTPS origin | served over plain HTTP — a browser installs only from a secure origin |
| Root of a hostname | mounted under a path prefix; manifest start_url/scope are /, and /sw.js is served with Service-Worker-Allowed: / |
| Identity resolves to an agent | the request lands on the operator grid, which carries no manifest link, no service-worker registration and no iOS meta tags |
agentctl handles neither TLS nor DNS. The cockpit binds :8731 and webview-login
proxies it on :8736; put your own HTTPS proxy in front. See
The webview gateway.
/manifest.webmanifest, /sw.js, /icons/ and /fonts/ bypass the login proxy and answer
unauthenticated. Do not gate them at your proxy — iOS Safari fetches them without a session
to decide whether to offer the install.
Install¶
iOS, iPadOS¶
- Open the cockpit in Safari. No other iOS browser can install.
- Tap Share.
- Tap Add to Home Screen → Add.
Android¶
- Open the cockpit in Chrome.
- Open the browser menu (⋮).
- Tap Install app (or Add to Home screen).
Desktop (Chrome, Edge)¶
- Open the cockpit.
- Click the install control in the address bar, or menu → Install.
- The app opens in its own window with no address bar.
Behaviour once installed¶
| Area | Behaviour |
|---|---|
| Offline | None. /sw.js passes every request to the network and precaches nothing. An unreachable host shows the browser's network error page. |
| Upgrades | The next launch is already the new UI. No update prompt, no version skew. |
| Notifications | Page notifications only, plus vibration on Android. Requires the document open with its stream connected. |
| Closed app | Produces nothing. There is no Push API subscription and no badging. |
| Unread count | Written into the document title — visible on a browser tab, not on an installed app. |
| Wake from sleep | The stream re-opens on visibilitychange and on bfcache restore, and re-seeds turn state from the transcript. Nothing to configure. |
| Session | The cookie lasts 30 days. Override with WEBVIEW_SESSION_TTL (any Go duration, e.g. 168h). |
The cockpit asks for notification permission when an agent's cockpit opens, and again on the first message you send.
Name, icon and colours¶
The shipped binary carries no branding. Override per host:
agentctl host set webview_icon '<data:image URI or https URL>'
agentctl host set webview_bg '#0b0e14'
agentctl host set webview_app_name 'Acme'
| Scalar | Applies to | Default |
|---|---|---|
webview_icon |
the app icon (192 and 512) | neutral agentctl icon |
webview_bg |
manifest theme_color and background_color |
#0b0e14 |
webview_app_name |
appended to the agent name in the manifest name |
unset |
The installed app's label differs by platform:
| Platform | Label source | Value |
|---|---|---|
| iOS home screen | apple-mobile-web-app-title, rendered into the authenticated document |
the agent's name |
| Android, desktop | manifest name, produced for an unauthenticated request with the identity header stripped |
always agentctl; webview_app_name does not reach it |
Colours and icons are unaffected — they are read from host config, not from the request.
Icon URLs carry ?v=<content hash>, so a changed icon gets a fresh URL. Some installs cache
the home-screen icon against the URL path and ignore the query. After you change
webview_icon, expect existing installs to keep the old icon until the user reinstalls.
Basic auth driver¶
Sign in through the HTML form, not an Authorization header. A standalone PWA suppresses
the browser's native 401 prompt, and per-request Basic replay through a service worker is
unreliable. Scripts and API clients can still send Basic preemptively.