Files
opencode-mobile/distribution/retention-analysis.md
Den d54a74d3f5 fix(onboarding): clarify opencode-serve requirement + fail connect fast (retention) (#107)
* fix(onboarding): clarify opencode-serve requirement and fail connect tests fast

New users bounce at ~0% 7-day retention because nothing tells them the app
needs a computer running `opencode serve` on the same network/Tailscale, and
a bad IP hangs for the full 30s request timeout before failing.

- Rewrite the no-connection empty state subtitle and add a "How to set up a
  server" link to the setup guide (app/(tabs)/index.tsx, src/lib/links.ts).
- Surface the opencode-serve prerequisite as a one-line notice at the top of
  the Quick Connect form, above the existing detailed help box
  (app/connection/add.tsx).
- Give the interactive connection test (testConnection) its own 12s timeout
  via an optional Client.global.health(timeoutMs) parameter, instead of
  reusing the general 30s REQUEST_TIMEOUT_MS used for real session traffic
  (src/lib/sdk.ts, src/stores/connections.ts).
- Mirror all new/changed strings in the zh-Hans catalog; catalog-parity test
  keeps them in sync.

* docs(distribution): add retention analysis motivating first-run fixes

Diagnoses ~0% D7 retention as product-shape (no path to value without a
self-hosted server, no demo mode, store copy sets no expectation). Ranks
fixes and isolates the two owner-only strategic calls (store-copy honesty,
hosted OpenCode Connect).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T12AhSnQVrSxNnvwfCx2z6

* fix(onboarding): drop connect-screen prerequisite notice (kept off-screen the submit button in E2E)

The added notice pushed connect-submit-button below the fold, breaking the
Maestro activation-positive flow (and the other flows sharing the connect
prelude). The empty state already sets the opencode-serve expectation one
screen earlier, so this notice was redundant. Empty-state guidance + guide
link and the fast-fail connect timeout are unaffected and retained.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T12AhSnQVrSxNnvwfCx2z6

---------

Co-authored-by: engineer <engineer@macbookpro.lan>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 17:55:12 -07:00

4.0 KiB
Raw Blame History

Retention Analysis — opencode-mobile

Last updated: 2026-07-17

The number that matters

  • Installs: 1K+ (Google Play, live listing, package cc.agentlabs.opencode).
  • 7-day retention: ~0% (per Notion "Retention Investigation").

Awareness is not the bottleneck anymore. Getting people to install works. Getting them to stay does not. Every hour spent on more distribution channels is spent on the wrong problem until activation is fixed.

Diagnosis: it's product-shape, not a bug

A brand-new installer's path (traced in code):

  1. Launch → telemetry consent modal first (app/_layout.tsx:157-168) — a privacy prompt before the user has seen any value.
  2. Land on Sessions tab, empty state: "No Connection / Add a server connection to get started" (app/(tabs)/index.tsx:421-440, src/lib/i18n/en.json:258-259). No hint that this needs a separate computer.
  3. Tap Add → Quick Connect form asking for IP address + port + password (app/connection/add.tsx:225-407), hand-typed on a phone keyboard.
  4. To get past this, the user must already have, on another machine: Node/npm, opencode-ai installed, opencode serve running, and LAN or Tailscale reachability.
  5. A wrong IP hangs the spinner up to 30s before any feedback (REQUEST_TIMEOUT_MS=30_000, src/lib/sdk.ts:175).

There is no demo, sample, or try-it mode anywhere in the app. For any installer without a self-hosted server already running — almost certainly the majority of casual Play installs — the app is functionally inert after onboarding: empty state → a form they can't fill → a "coming soon" mailing-list card (app/connection/add.tsx:343-397). Nothing else to tap.

The store listing makes it worse: the short description ("AI coding agent in your pocket. Stream, diff, approve — free & open source.") sets zero expectation that a self-hosted server is required. People install expecting a standalone app, hit a wall, and uninstall. That is the ~0% D7 mechanism.

Fixes, ranked by impact ÷ effort

# Change Impact Effort Owner-gated?
1 Set the self-hosting expectation in the empty state + connect screen; fail-fast timeout High Low No — shipping via PR
2 One-screen "what you need" pre-flight with an "I don't have a server yet" branch High Med No
3 QR-code pairing (server prints QR of URL+creds; app scans) — kills manual IP/port/password typos High Med No
4 Local demo/sandbox session — scripted walkthrough of chat/diff/approve, no server needed High Med-High No
5 Store-copy honesty: move the server prerequisite into the short description + first screenshot High (on D7) Low Yes — Play Console
6 Hosted "OpenCode Connect" so users need no server at all (the real fix) Highest High Yes — strategic/infra

Items 1–4 are agent-shippable. Item 1 is in flight (branch fix/first-run-onboarding-clarity).

The one decision only the owner can make

Do we optimize for install count or for activated users?

  • Item 5 (put "needs a self-hosted server" in the store's short description) will reduce installs — it filters out people who can never activate. It will raise retention and store rating quality. This is a positioning tradeoff, not an engineering one, so it is the owner's call, not an agent's. Recommended: yes, be honest up front — a 4-star app with 300 real users beats a 2-star app with 1,000 bouncing ones.
  • Item 6 (hosted OpenCode Connect) is the only change that removes the server prerequisite entirely. The waitlist card already in the app signals intent. This is the actual long-term retention fix and deserves a roadmap decision.

What this loop is doing about it

  • Shipping items 1 (and scoping 2) as reviewable PRs.
  • Not touching the live Play listing (item 5) or infra (item 6) — surfacing them here for the owner instead of acting unilaterally on positioning/strategy.