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

73 lines
4.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.