- App in review as of 2026-06-21 (versionCode 32) - Website live at opencode.agentlabs.cc - CUA test rewritten with full onboarding showcase - Next actions: wait for review, keep demo server alive, announce on approval Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01No3k1AEioE4PNUZg12TxQo
283 lines
16 KiB
Markdown
283 lines
16 KiB
Markdown
# OpenCode Mobile — Handoff (2026-06-21)
|
||
|
||
App: **`cc.agentlabs.opencode`** (OpenCode Mobile) — Expo/React Native Android client
|
||
for a user self-hosted opencode AI server. Owner: VIBE TECHNOLOGIES, LLC.
|
||
Repo: `dzianisv/opencode-mobile`. Full running log: `context.md`.
|
||
Goal: bug-free E2E + published on F-Droid & Play + 1k downloads.
|
||
|
||
---
|
||
|
||
## TL;DR status
|
||
|
||
| Goal | State |
|
||
|---|---|
|
||
| #1 App works E2E, no bugs | ✅ Done & verified (CUA smoke green; 4 bugs fixed) |
|
||
| #2 F-Droid published | ✅ self-hosted repo LIVE @ v0.4.3 |
|
||
| #3 Google Play published | 🟡 **"Changes in review"** — v0.4.5 (VC32) submitted 2026-06-21, awaiting Google approval (up to 7 days) |
|
||
| #4 Store optimization (ASO) | ✅ YouTube video + 4 CUA screenshots + ASO copy live in listing |
|
||
| #5 Website live | ✅ `https://opencode.agentlabs.cc` live (Vercel, SSL) |
|
||
| #6 1k downloads | ❌ needs Google approval → announce |
|
||
|
||
---
|
||
|
||
## Session 2026-06-21: what was done
|
||
|
||
### Play Store — submitted to production
|
||
- Built AAB v0.4.5 (versionCode=32) locally, signed with Bitwarden keys
|
||
- Uploaded to internal track via Play Developer API
|
||
- Promoted to production: 100% rollout to 177 countries
|
||
- Resolved "Missing sign-in details" blocker — added demo server `http://100.108.64.76:4096` + reviewer instructions
|
||
- **Status: "Changes in review" as of 2026-06-21**
|
||
|
||
### Play Store listing
|
||
- YouTube demo video: `https://www.youtube.com/watch?v=ckAHcfZKuUY` (Unlisted Short, Vibe Technologies channel `UCyq0vIekTqyLDFakzHxkJtA`)
|
||
- 4 CUA screenshots uploaded (1080×2160): empty state, add connection, AI chat, session list
|
||
|
||
### Website
|
||
- `https://opencode.agentlabs.cc` live — Vercel project `opencode-mobile-site`
|
||
- DNS: A + TXT records added in Spaceship for `agentlabs.cc`
|
||
- Vercel domain verified via API, SSL cert auto-provisioned
|
||
|
||
### CUA test rewritten
|
||
- `scripts/android-cua-smoke.py` — full onboarding showcase (6 phases)
|
||
- Phases: connect → session_list → new_session → typescript task → verify → settings
|
||
- `--speed-multiplier` flag for fast video recording
|
||
- Committed: `3c49897`
|
||
|
||
### versionCode bumped
|
||
- `app.json` + `android/app/build.gradle` both set to 32, versionName `0.4.5`
|
||
- Committed: `db75606`
|
||
|
||
---
|
||
|
||
## NEXT ACTIONS (priority order)
|
||
|
||
---
|
||
|
||
### 1. Wait for Google review (ETA: up to 7 days)
|
||
Check: Play Console → Publishing overview
|
||
URL: `https://play.google.com/console/u/1/developers/8842655543970815326/app/4973009715197528834/publishing`
|
||
If rejected: read exact rejection reason, fix, resubmit.
|
||
Account: `vibeteaichnologies@gmail.com`
|
||
|
||
### 2. Keep demo server alive during review
|
||
Google reviewers use `http://100.108.64.76:4096` (Tailscale host `openclaw-dev-1`).
|
||
**Keep this server running until review completes** — if reviewers can't connect, app gets rejected.
|
||
|
||
### 3. Announce once approved (in this order)
|
||
1. **HN Show HN** — Tuesday–Thursday 8–10am ET. Template in `opencode-mobile-demo-to-store` skill.
|
||
2. **Twitter/X thread** — 30 min after HN
|
||
3. **Reddit** — r/androiddev, r/selfhosted, r/artificial (Day 2)
|
||
4. **Product Hunt** — Day 3
|
||
|
||
### 4. Re-record demo video (post-review)
|
||
Current video (`ckAHcfZKuUY`) is slow, shows old flow.
|
||
```bash
|
||
source ~/.env.d/azure-openai.env
|
||
adb shell screenrecord --time-limit 180 /sdcard/demo.mp4 &
|
||
python3 scripts/android-cua-smoke.py --model gpt-4o --speed-multiplier 0.5
|
||
adb pull /sdcard/demo.mp4 /tmp/demo.mp4
|
||
```
|
||
Upload to Vibe Technologies YouTube channel via VBC DataTransfer injection (see `android-cua-demo-recording` skill).
|
||
Then update Play Store listing video URL via Play Developer API.
|
||
|
||
### 5. More screenshots (optional, improves conversion)
|
||
Add diff viewer + tool-call approval screenshots. Upload via Play Developer API (see `opencode-mobile-demo-to-store` skill Phase 3).
|
||
|
||
---
|
||
|
||
## App URLs
|
||
|
||
- **Direct APK (works now):** https://github.com/dzianisv/opencode-mobile/releases/latest
|
||
- **F-Droid self-hosted repo:** https://dzianisv.github.io/opencode-mobile/fdroid/repo
|
||
(add this URL in any F-Droid client). **LIVE @ v0.4.3** — verified 2026-06-02.
|
||
- **Google Play (NOT public yet):** https://play.google.com/store/apps/details?id=cc.agentlabs.opencode
|
||
— 404s until production rollout; internal-testing track has v0.4.3.
|
||
- **F-Droid mainline (pending MR #39530):** https://f-droid.org/packages/cc.agentlabs.opencode/
|
||
|
||
---
|
||
|
||
## What was done this session (committed to `main`)
|
||
|
||
**Bug fixes (goal #1) — `npm run typecheck` + `npm test` green, E2E smoke verified:**
|
||
- `0615ab8` gradle versionName 0.4.1→0.4.2 (stale vs app.json)
|
||
- `bed0b6f` #10 root cause: single `src/stores/sessionScope.ts` helper so session
|
||
list/create scopes can't drift; `node:test` regression guard + `npm test` script
|
||
- `66b89f7` 2nd scope bug: created session opened/sent via wrong client (nav lacked
|
||
`directory`); now stamped on the session + passed through
|
||
- `059b5cc` send-failure after a session switch flashed error on / refetched the
|
||
wrong session
|
||
- Full runtime audit (dismissed 2 false-positives with evidence).
|
||
- **CUA smoke GREEN** (run 26803479355): connect→create→list passes (was the #10 repro).
|
||
|
||
**Publishing (goals #2/#3):**
|
||
- `c66f4fb` cut **v0.4.3** (versionCode 5).
|
||
- `eea84a3` **F-Droid publish fix**: pin `androguard==4.1.3` (the `==4.1.4` pin added
|
||
2026-06-01 crashed in `parse_v2_v3_signature`) + apksigner v1+v2-only re-sign step in
|
||
`publish-fdroid.yml`. **Verified locally** that 4.1.3 parses the APK signer cert.
|
||
- Tag `v0.4.3` re-pointed → re-runs the F-Droid publish (in flight at handoff).
|
||
- Play **internal track** auto-published v0.4.3 via `publish-play-store.yml` (success).
|
||
- `67773fc` corrected IzzyOnDroid doc (was stale `ai.opencode.mobile`).
|
||
|
||
---
|
||
|
||
## OWNER ACTIONS REQUIRED — only these unblock #2/#3/#5 (agent cannot do them)
|
||
|
||
0. **Push the local commits (push is permission-gated for the agent — harness blocks `git push`).**
|
||
**17 commits unpushed on `main`** as of 2026-06-08 (run `git log origin/main..main --oneline`
|
||
to confirm). All reach ZERO users until pushed — this is the dominant growth bottleneck.
|
||
Owner approved "push + tag v0.4.4" but the harness denies the agent's `git push`; owner must run it.
|
||
Highlights: SEO pages `/features/`, `/download/`, `/troubleshooting/`, `/comparison/`,
|
||
`/vs-termux/`, `/claude-code-android/`, `/opencode-on-phone/` (targets proven "setup opencode on
|
||
phone" query); landing screenshot strip; ASO copy (keyword title + fixed dead privacy URL);
|
||
README non-affiliation note; CI typecheck+tests; test coverage 4→65; version bump 0.4.3→0.4.4.
|
||
Run (owner):
|
||
```
|
||
cd /Users/engineer/workspace/opencode-mobile && source ~/.env.d/github-dzianisv.env
|
||
git push origin main # deploys site (safe, no release)
|
||
git tag v0.4.4 && git push origin main --tags # fires F-Droid + Play publish
|
||
```
|
||
|
||
0b. **HARD GATE — test a real public release before ANY public/community posting (owner directive
|
||
2026-06-08).** Automated unit tests are NOT sufficient (no 100% coverage). Before posting to
|
||
HN / Reddit / PH / socials, a built release APK must be manually exercised across all core flows
|
||
(add-connection, session list, streaming chat, tool-call approve/reject, diff viewer, biometric
|
||
unlock) on a real device/emulator and confirmed free of bugs and UI/UX defects. The CUA smoke
|
||
currently runs `--only-connect-scenario` only — EXPAND it to all scenarios + human-review the
|
||
captured screenshots/video before greenlighting any public launch post.
|
||
The session-scope fix is not yet in any release. To ship it, bump the version in
|
||
BOTH `app.json` (line 5: `"version": "0.4.3"` → `"0.4.4"`) and
|
||
`android/app/build.gradle` (line 98 `versionName "0.4.3"` → `"0.4.4"`; leave
|
||
`versionCode` — Play's is auto-set to `github.run_number`, F-Droid reads versionName),
|
||
commit, then `git tag v0.4.4 && git push origin main --tags`. The `v*` tag fires
|
||
`publish-fdroid.yml` and `publish-play-store.yml` automatically.
|
||
|
||
1. **Privacy policy is live (Play-production blocker cleared).** Canonical privacy URL is
|
||
now `https://dzianisv.github.io/opencode-mobile/privacy/` — live & verified (HTTP 200) on
|
||
the gh-pages branch, serving `distribution/privacy-policy.html`. This GitHub Pages URL is
|
||
the canonical privacy URL cited across all store-submission docs (Play "App content"
|
||
answers, IzzyOnDroid request). If the owner later deploys the branded
|
||
`opencode.vibebrowser.app/privacy`, it can replace the GitHub Pages URL — this change is
|
||
reversible. Source file: `distribution/privacy-policy.html` (markdown mirror:
|
||
`distribution/privacy-policy.md`).
|
||
|
||
2. **Google Play → production (biggest unlock, ~15 min).**
|
||
Play Console → app → Monitor and improve → Policy → **App content**. Complete the
|
||
declarations using the pre-written, code-verified answers in
|
||
`distribution/PLAY-APP-CONTENT-ANSWERS.md`. Then Production → create release → add
|
||
the v0.4.3 AAB (CI already uploaded) → roll out → submit for review.
|
||
|
||
2. **F-Droid reach (any/all):**
|
||
- Self-hosted repo updates automatically once the in-flight publish run is green —
|
||
just share the repo URL above. (Verify: command below.)
|
||
- **IzzyOnDroid** (fast, popular): file the inclusion issue at
|
||
https://codeberg.org/IzzyOnDroid/repodata/issues using
|
||
`distribution/izzyondroid-submission/INCLUSION-REQUEST.md` (needs a Codeberg account).
|
||
- **Mainline F-Droid**: MR #39530 is filed and open at
|
||
https://gitlab.com/fdroid/fdroiddata/-/merge_requests/39530 (needs a gitlab.com
|
||
account that is a member of the MR, i.e. the account that filed it). Open the MR,
|
||
read the maintainer's review comments/CI (fdroid build pipeline) under the
|
||
"Activity"/"Pipelines" tabs, address any requested metadata changes by editing
|
||
`metadata/cc.agentlabs.opencode.yml` on the MR's source branch (local source:
|
||
`distribution/fdroid-submission/metadata.yml`), push, and reply to each reviewer
|
||
thread. If CI is red, fix per the build log and re-push the source branch.
|
||
|
||
3. **Growth → 1k downloads:** post the launch kit in `distribution/launch/`
|
||
(Show HN, Product Hunt, Reddit, X, dev.to) from your accounts, following the fire
|
||
sequence in `distribution/launch/LAUNCH-CHECKLIST.md`.
|
||
**Gate:** every post file contains `{{PLAY_URL}}` / `{{FDROID_URL}}` placeholders —
|
||
do NOT post any file that still has a `{{...}}` token. Replace:
|
||
`{{FDROID_URL}}` → `https://dzianisv.github.io/opencode-mobile/fdroid/repo` (live now);
|
||
`{{PLAY_URL}}` → `https://play.google.com/store/apps/details?id=cc.agentlabs.opencode`
|
||
(only valid after item 2's production rollout is live — until then, link the F-Droid
|
||
repo + GitHub releases instead). ASO copy in `distribution/play-listing.md` /
|
||
`distribution/app-store-listing.md`.
|
||
|
||
---
|
||
|
||
## RENDER-CHECK — 5-min manual gate (the ONE path CI can't test)
|
||
|
||
CI's opencode has no model provider, so it can't verify send→reply→**render**. This machine
|
||
CAN serve a model-capable opencode (proven 2026-06-08: Gemini replies via opencode). What's
|
||
missing is a bootable device to view the reply in the app. Once a device exists, do this:
|
||
|
||
```bash
|
||
# 1. Model-capable opencode server (Gemini). Use an ISOLATED config dir — do NOT edit
|
||
# the global ~/.config/opencode/opencode.json.
|
||
mkdir -p /tmp/oc-gemini && cd /tmp/oc-gemini
|
||
cat > opencode.json <<'JSON'
|
||
{ "$schema":"https://opencode.ai/config.json",
|
||
"provider": { "google": { "npm":"@ai-sdk/google" } },
|
||
"model": "google/gemini-2.5-flash" }
|
||
JSON
|
||
GOOGLE_GENERATIVE_AI_API_KEY="$GEMINI_API_KEY" opencode serve --hostname 0.0.0.0 --port 4096
|
||
# sanity (note: model is NESTED, and use a REAL catalog id like gemini-2.5-flash,
|
||
# NOT gemini-2.0-flash — wrong shape/id returns an empty 200 with no reply):
|
||
# SID=$(curl -s -X POST localhost:4096/session -d '{}' | jq -r .id)
|
||
# curl -s -X POST localhost:4096/session/$SID/message -H 'content-type: application/json' \
|
||
# -d '{"model":{"providerID":"google","modelID":"gemini-2.5-flash"},
|
||
# "parts":[{"type":"text","text":"hi in one word"}]}' | jq '.parts[]|select(.type=="text").text'
|
||
|
||
# 2. Boot a device. PREFER the external Android disk (AGENTS.md: do NOT use system disk):
|
||
# plug in the disk, then:
|
||
export ANDROID_HOME=/Volumes/Dzianis-3/macbook2020/android-sdk
|
||
export ANDROID_AVD_HOME=/Volumes/Dzianis-3/macbook2020/android-avd
|
||
export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator:$PATH"
|
||
emulator -avd test -no-audio -no-boot-anim -gpu swiftshader_indirect -no-snapshot -port 5554 &
|
||
adb wait-for-device
|
||
until [ "$(adb shell getprop sys.boot_completed 2>/dev/null)" = "1" ]; do sleep 2; done
|
||
|
||
# 3. Install + launch the prebuilt release APK (already built, valid):
|
||
adb install -r ~/workspace/opencode-mobile/android/app/build/outputs/apk/release/app-release.apk
|
||
adb shell am start -n cc.agentlabs.opencode/.MainActivity
|
||
```
|
||
|
||
4. In the app: Add Connection (quick mode) → IP `10.0.2.2`, port `4096` → connect →
|
||
New Session → send: **"write a Python function that reverses a string, then show it as a diff"**.
|
||
5. Wait for the Gemini reply, then EYEBALL the three surfaces and screenshot each
|
||
(`adb exec-out screencap -p > ~/render-<surface>.png`):
|
||
- **markdown**: heading/bold/bullets render as formatting, not raw `#`/`*`.
|
||
- **fenced code block**: monospace, has a language header + Copy button, and a LONG line
|
||
scrolls HORIZONTALLY (not cut off / not wrapped to mush). To force a long line, also try:
|
||
"show a python function call with 30 arguments named arg1..arg30 on one line".
|
||
- **diff**: a literal "show as a diff" prompt usually yields a ```diff fenced block → renders
|
||
via CodeBlock (fine). The dedicated DiffView (green/red +/- lines) only appears when the
|
||
agent uses the `edit`/`apply_patch` TOOL; to exercise it, ask the agent (in a real project
|
||
dir) to actually edit a file.
|
||
If all three look right with no truncation/overflow/cutoff → the core path is release-ready.
|
||
|
||
## Verify / common commands
|
||
|
||
```bash
|
||
npm run typecheck # tsc --noEmit (clean)
|
||
npm test # node:test suite (4 passing)
|
||
gh run list --workflow=publish-fdroid.yml --limit 3 # F-Droid publish status
|
||
gh run list --workflow=cua-smoke.yml --limit 3 # E2E smoke status
|
||
# Is the live F-Droid repo updated to cc.agentlabs.opencode @ v0.4.3?
|
||
curl -s https://dzianisv.github.io/opencode-mobile/fdroid/repo/index-v1.json | \
|
||
python3 -c "import sys,json;d=json.load(sys.stdin);print({p:[v['versionName'] for v in vs] for p,vs in d['packages'].items()})"
|
||
```
|
||
|
||
## Gotchas / notes
|
||
- `expo prebuild` regenerates `android/build.gradle` in CI → enforce signing in the
|
||
workflow (apksigner re-sign step), not only in gradle.
|
||
- F-Droid breaks on androguard 4.1.4 (`'NoOverwriteDict' has no attribute 'append'`);
|
||
use **4.1.3**. The published APK must be **v1+v2-only** (no v3) for it to parse.
|
||
- Play `versionCode` = `github.run_number` (auto-monotonic); re-tagging won't collide.
|
||
- F-Droid publish triggers on `v*` tags only (agent has **no admin** to
|
||
`workflow_dispatch`/rerun; can push commits/tags).
|
||
- Session directory-scope invariant: all session ops must use `sessionScopeDirectory`
|
||
or sessions go invisible (this was bug #10).
|
||
- Shared browser (chrome-devtools over Tailscale) was offline this session, so
|
||
browser-driven console/Codeberg steps couldn't be attempted.
|
||
|
||
## Infra references (durable)
|
||
- OpenCode server (testing): `100.108.64.76:4096` (Tailscale host `openclaw-dev-1`).
|
||
- CUA smoke vision model: Azure `gpt-5.4`; endpoint
|
||
`https://info-mjnxtt51-eastus2.cognitiveservices.azure.com`; gpt-5.x needs
|
||
`max_completion_tokens` (not `max_tokens`). Secrets in repo Actions.
|
||
- GitHub auth (local): `source ~/.env.d/github-dzianisv.env`.
|
||
- Signing: production key SHA-256
|
||
`0C:25:9D:94:E0:FF:EA:5D:63:19:61:4B:22:9D:4B:6B:DC:22:DE:1F:56:E3:8E:76:94:83:98:D2:DF:6A:A0:99`
|
||
(same key across Play / F-Droid / IzzyOnDroid — in-place updates work).
|