Repository Public
1# Mobile experience23The same static web application serves phones, tablets and desktops. Below 768 px it switches to a4purpose-built phone layout. Source: `apps/web/src/components/shell/mobile-shell.tsx`,5`components/terminal/{mobile-terminal,mobile-toolbar,keys,touch,controller}.ts(x)`,6`hooks/use-viewport.ts`, `public/{sw.js,manifest.webmanifest}`.78**Verification status: WebKit iPhone 15 emulation in Playwright only. Nothing in this document has been9verified on a physical iPhone, in Safari or as an installed PWA.**1011## Layout1213| Breakpoint | Width | Shell |14|---|---|---|15| mobile | < 768 px | phone shell: top bar, full-bleed content, bottom navigation |16| tablet | 768–1023 px | desktop shell components at a narrower width |17| desktop | ≥ 1024 px | sidebar, tabbed terminal workspace, right panel |1819Phone shell:2021- The root element is `position: fixed` and sized from `window.visualViewport` (CSS variables `--vvh`,22 `--vvt`), so its bottom edge is the top of the software keyboard. iOS scrolls the layout viewport to23 reveal a focused field; the shell undoes that scroll.24- Bottom navigation: Terminal, Projects, Files, Tasks, Cluster, plus a "More" entry (Sessions, Skills,25 MCP, System, Settings). It hides while the keyboard is open.26- `viewport-fit=cover`; touch targets are at least 44 px high on coarse pointers.27- Files use a drill-down list and a full-screen editor instead of the desktop split view.2829## Terminal on a phone3031`MobileTerminal`: a top bar (session title, state, connection indicator), the terminal edge to edge, and32the key toolbar directly above the keyboard.3334- A session sheet lists the sessions for switching; a swipe from the left edge opens it.35- The terminal font size comes from the `mobileFontSize` setting (default 12, range 8–28) and can be36 changed by pinching.37- On iOS the terminal uses xterm.js's DOM renderer (the WebGL renderer is used elsewhere when available).38- One WebSocket per session, same protocol as on desktop; the terminal is re-fitted on rotation and when39 the keyboard opens or closes, and the new size is sent to the server.4041### Key toolbar4243Default keys (`mobileToolbar` in the user settings — the list is configurable):4445`esc` `tab` `ctrl` `alt` `shift` `↑` `↓` `←` `→` `enter` `/` `|` `~` `-`, followed by **Paste** (reads the46clipboard) and **Hide keyboard**.4748- Buttons act on `pointerdown` with `preventDefault` and are not focusable, so the terminal keeps focus49 and the keyboard stays open.50- Sticky modifiers (`ctrl`, `alt`, `shift`): one tap = applies to the next key only; double tap = locked;51 tap while locked = off. They apply both to toolbar keys and to characters typed on the software52 keyboard (for example `ctrl` then `c` sends `0x03`).53- Arrow keys honour the application cursor mode reported by xterm.js (DECCKM), so they work in programs54 that switch it.55- Keys that make sense repeated auto-repeat when held (after 420 ms, every 70 ms).56- The toolbar scrolls horizontally if it does not fit.5758### Touch gestures5960| Gesture | Effect |61|---|---|62| Tap | focuses the terminal (opens the keyboard), clears a previous selection |63| One-finger drag | scrolls the scrollback with momentum; when the application inside tracks the mouse, wheel reports are sent instead |64| Long press (420 ms), then drag | starts and extends a text selection |65| Two-finger pinch | changes the font size |6667## Connection behaviour on mobile networks6869Identical to desktop, and designed for it (see [session-persistence.md](session-persistence.md)):7071- The session keeps running on the server whatever the phone does.72- Reconnect with backoff (0.5 s → 10 s) and immediately when the page becomes visible, the network comes73 back, or the page is restored from the back/forward cache.74- A connection that looks open after a suspension is probed with a ping and replaced if it does not75 answer within 2.5 s.76- Every re-attach replays the history and repaints the screen.77- While offline the terminal shows "Offline — the session keeps running on the server"; keystrokes are78 not queued.7980## Installable shell (PWA)8182- `manifest.webmanifest`: name "Claude Remote", `display: standalone`, `start_url: /terminal/`,83 192/512 px icons (regular and maskable); Apple touch icon and `apple-mobile-web-app-capable`84 metadata are set in `app/layout.tsx`.85- `sw.js` (registered in production builds only) caches the **static application shell**: the HTML shells86 of the routes, `/_next/static/*`, fonts, icons and the manifest. Navigations are network-first with the87 cached shell as fallback; content-hashed assets are cache-first.88- `/api/*` is never intercepted and never cached; WebSockets cannot be. No terminal data, API response or89 credential is stored by the service worker.90- Offline, the cached shell loads and shows an explicit offline state. Nothing can be done offline.9192## Notifications on mobile9394In-app only: a notification list and toasts while the application is open, fed by the events WebSocket95(`session.waiting`, `session.exited`, `task.succeeded`, `task.failed`). There is no push notification96when the application is closed or suspended.9798## Tests99100`apps/web/e2e/mobile.spec.ts`, Playwright project `mobile` (`devices['iPhone 15']`, WebKit), against the101dev mock API — 4 tests, all passing on 2026-11-10:1021031. login, purpose-built layout, toolbar above the terminal, no horizontal overflow;1042. toolbar keys send real sequences; sticky modifiers (one-shot, lock); focus is kept;1053. session sheet, switching, font size, files drill-down with full-screen editor;1064. larger phone (430 × 932) and landscape refit.107108Key sequences and sticky-modifier logic are also unit-tested (`apps/web/src/__tests__/keys.test.ts`).109`apps/web/e2e/setup-offline.spec.ts` covers the offline shell.110111## Limitations / not verified112113- **No real-device test.** Not verified: Safari on a real iPhone, the installed PWA in standalone mode,114 the real iOS software keyboard and `visualViewport` behaviour, iOS suspension and resume, clipboard115 permission prompts for Paste, safe-area insets on real hardware, Android browsers.116- Emulation runs WebKit on macOS with a touch-enabled viewport; it does not reproduce the iOS keyboard,117 Safari's toolbar, or background suspension.118- The mobile tests run against the mock API, not the real backend.119- Web Push is not implemented. The `webPush` setting is stored, but the client does not subscribe and the120 server does not send. A phone will not be alerted that a session is waiting unless the application is open.121- iOS may evict a suspended PWA; the application then reloads and re-attaches (the session is unaffected),122 but this path was not observed on a device.123- Hardware keyboards on tablets, split view and stage manager were not tested.124- The laptop-independence test (laptop off, phone on cellular) has not been run.125