feat(privacy+dist): telemetry consent gate + app store distribution prep (#4)
* fix(security): fail closed on biometric init error H-03: setting isAuthenticated: true on initialization failure was a security bypass — any crash during biometric setup granted full access. Fail closed instead; user sees auth prompt on next open. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(security): use Crypto.randomUUID for connection IDs H-04: Math.random() is not cryptographically random. Connection IDs are used as SecureStore key suffixes; switch to expo-crypto randomUUID for a secure source. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(deps): pin expo-crypto to ~15.0.9 15.0.10 does not exist on npm; ~15.0.9 is the latest stable in the 15.x series compatible with Expo SDK 54. * feat: add OpenCode Connect coming-soon waitlist card Adds a discoverable 'OpenCode Connect — Coming Soon' card to the add-connection quick-connect screen. Users can enter their email and tap 'Join Waitlist' to send a pre-filled mailto. No backend required. * fix(cua): detect actual screen dimensions and fix JSON parsing - Get real screen size via `wm size` instead of hardcoding 1080x2400; emulator is 1080x1920 so y-coordinates were systematically off - Extract first JSON object via regex when model returns multiple objects - Use AZURE_OPENAI_MODEL env var for deployment name (defaults gpt-5.4) - Add AZURE_DEV_AI_* path for Azure AI Foundry endpoints Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(security): SHA-pin upload-google-play and sanitize notification bodies M-02: Pin r0adkll/upload-google-play to commit SHA e738b9d (v1.1.5) to prevent supply-chain hijack via tag mutation. M-03: Sanitize all push notification bodies — strip control chars, truncate to 200 chars. Prevents server-supplied strings (error messages, file paths from permission patterns, session titles) from leaking unbounded text into the OS notification drawer. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(privacy): add telemetry consent gate for Sentry crash reporting Sentry was always-on, violating F-Droid anti-feature policy and user trust norms. Now gated behind explicit opt-in: - First-launch consent modal (TelemetryConsentModal) shows once on fresh install; user can Allow or Decline. - Consent state persisted in expo-secure-store (survives restarts). - Settings > Privacy section: crash reporting toggle + privacy policy link. - initSentry() called only after consent granted — not on app start. Closes #3 (partial) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(config): add real icons and complete iOS/Android app.json config - Add 1024×1024 app icon, 432×432 adaptive icon foreground, 200×200 splash - iOS: push notification entitlement (aps-environment: production), speech/ microphone/camera/photo usage descriptions for future features, disable ITSAppUsesNonExemptEncryption - Android: adaptive icon with dark background (#0F172A), versionCode: 1 - expo-notifications plugin wired in app.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(dist): add iOS CI workflow, README rewrite, CONTRIBUTING, and LICENSE - publish-app-store.yml: EAS Build + TestFlight submission; runs on tag/release/ workflow_dispatch; bumps ios.buildNumber from github.run_number - README: full rewrite — features, install badges, connection guide, contributing - CONTRIBUTING.md: contribution guide for OSS contributors - LICENSE: MIT Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(dist): add store listings, strategy, privacy policy, F-Droid/IzzyOnDroid templates - distribution/strategy.md: monetization strategy (free client + opencode Cloud) - distribution/play-listing.md: Google Play store copy (name, description, tags) - distribution/app-store-listing.md: App Store listing copy - distribution/privacy-policy.{md,html}: GDPR-compliant privacy policy - distribution/PLAY_CONSOLE_SETUP.md: Play Console setup runbook - distribution/ios-enrollment-runbook.md: Apple Developer Program enrollment steps - distribution/SIGNING-KEY-FINGERPRINTS.md: keystore fingerprint for reproducible builds - distribution/fdroid-submission/: F-Droid metadata template - distribution/izzyondroid-submission/: IzzyOnDroid submission template - distribution/whatsnew/: Play Store release notes (en-US) - distribution/whatsnew-ios/: TestFlight release notes - distribution/play-graphics/: Play Store screenshot placeholders - distribution/app-store-graphics/: App Store screenshot placeholders Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(telemetry): handle SecureStore failure + Android back button - add .catch() on loadTelemetryConsent() so SecureStore rejection shows the consent modal instead of blocking startup forever - add onRequestClose={onDecline} to Modal so Android back button records the decline rather than silently dismissing - fix catch block in telemetry.ts to not clobber _resolved when SecureStore read fails mid-session Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ci): run gradlew clean to prevent stale modules.json duplicate Sentry Gradle plugin writes modules.json to src/main/assets; cached build intermediates contain an old copy → mergeReleaseAssets fails with 'Duplicate resources'. Running clean before assembleRelease clears the intermediate state. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ci): remove android build output cache causing duplicate modules.json Caching android/app/build/intermediates and android/app/.cxx causes two issues: 1. Stale modules.json in intermediates → Duplicate resources error 2. .cxx CMake artifacts reference absolute paths → ninja clean fails Keeping only Gradle distribution cache (~/.gradle) which is safe. Expo prebuild regenerates android sources fresh each run anyway. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
64
distribution/SIGNING-KEY-FINGERPRINTS.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Signing Key Fingerprints — opencode-mobile
|
||||
|
||||
All distribution channels (Google Play, F-Droid, IzzyOnDroid) use the same
|
||||
signing key. This allows users to update in-place across stores.
|
||||
|
||||
Keystore: `keystores/production-release.jks`
|
||||
Key alias: (see Bitwarden item `KEYSTORE_INFO` in project folder `opencode-mobile`)
|
||||
|
||||
---
|
||||
|
||||
## SHA-256 Certificate Fingerprint
|
||||
|
||||
**Colon-separated (keytool / apksigner display format):**
|
||||
|
||||
```
|
||||
0C:25:9D:94:E0:FF:EA:5D:63:19:61:4B:22:9D:...:DF:6A:A0:99
|
||||
```
|
||||
|
||||
Full value (for file reference only — middle bytes intentionally omitted in reports):
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
**Lowercase without colons (F-Droid `AllowedAPKSigningKeys` format):**
|
||||
|
||||
```
|
||||
0c259d94e0ffea5d6319614b229d4b6bdc22de1f56e38e769483 98d2df6aa099
|
||||
```
|
||||
|
||||
(Remove the space — it is split here only for readability.)
|
||||
|
||||
---
|
||||
|
||||
## How to verify
|
||||
|
||||
```bash
|
||||
# From keystore
|
||||
keytool -list -v \
|
||||
-keystore keystores/production-release.jks \
|
||||
-storepass <STOREPASS> \
|
||||
| grep "SHA256:"
|
||||
|
||||
# From a signed APK
|
||||
apksigner verify --print-certs path/to/app-release.apk | grep SHA-256
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage in submissions
|
||||
|
||||
| Channel | Format needed | Location |
|
||||
|---------|--------------|----------|
|
||||
| F-Droid `AllowedAPKSigningKeys` | lowercase hex, no colons | `distribution/fdroid-submission/metadata.yml` |
|
||||
| IzzyOnDroid inclusion request | colon-separated | `distribution/izzyondroid-submission/INCLUSION-REQUEST.md` |
|
||||
| Google Play App Signing | uploaded via console | (Play manages separately if App Signing enabled) |
|
||||
|
||||
---
|
||||
|
||||
## Key backup
|
||||
|
||||
The keystore is gitignored. Backup location: Bitwarden project folder `opencode-mobile`,
|
||||
item `KEYSTORE_PRODUCTION_JKS`. Keep a second offline backup.
|
||||
|
||||
**Never commit the keystore or its password to git.**
|
||||
BIN
distribution/app-store-graphics/ipad-129/01.png
Normal file
|
After Width: | Height: | Size: 183 KiB |
BIN
distribution/app-store-graphics/ipad-129/02.png
Normal file
|
After Width: | Height: | Size: 190 KiB |
BIN
distribution/app-store-graphics/iphone-65/01.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
distribution/app-store-graphics/iphone-65/02.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
distribution/app-store-graphics/iphone-65/03.png
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
distribution/app-store-graphics/iphone-67/01.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
distribution/app-store-graphics/iphone-67/02.png
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
distribution/app-store-graphics/iphone-67/03.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
349
distribution/app-store-listing.md
Normal file
@@ -0,0 +1,349 @@
|
||||
# App Store Listing — OpenCode (iOS)
|
||||
|
||||
Copy-paste reference for App Store Connect. Use this once the Apple Developer Program enrollment is approved and the app is created in App Store Connect.
|
||||
|
||||
---
|
||||
|
||||
## App Information
|
||||
|
||||
### App Name (max 30 chars)
|
||||
|
||||
```
|
||||
OpenCode
|
||||
```
|
||||
(8 chars)
|
||||
|
||||
### Subtitle (max 30 chars)
|
||||
|
||||
```
|
||||
AI Coding Agent, In Your Pocket
|
||||
```
|
||||
(31 chars — trim to:)
|
||||
|
||||
```
|
||||
AI Coding Agent in Your Pocket
|
||||
```
|
||||
(30 chars exactly)
|
||||
|
||||
### Promotional Text (max 170 chars — appears above description, can be updated without a new review)
|
||||
|
||||
```
|
||||
Drive your self-hosted AI coding agent from anywhere. Connect to opencode on your workstation and review, approve, and guide AI-generated code changes in real time.
|
||||
```
|
||||
(165 chars)
|
||||
|
||||
### Description (max 4000 chars)
|
||||
|
||||
```
|
||||
OpenCode is an open-source mobile client for the opencode AI coding agent (github.com/sst/opencode). Connect to your self-hosted opencode server and drive AI-powered coding sessions directly from your iPhone or iPad.
|
||||
|
||||
KEY FEATURES
|
||||
|
||||
• Multiple connection types — local network (Wi-Fi), secure tunnels (Cloudflare Tunnel, ngrok), or cloud-hosted opencode instances
|
||||
• Biometric unlock — Face ID / Touch ID to keep your sessions private
|
||||
• Real-time streaming chat — watch your AI agent think and respond live as it works through your code
|
||||
• File diff viewer — see exactly what code changes the agent proposes before you accept them
|
||||
• Multi-session management — start, resume, and switch between coding sessions
|
||||
• Tool call approval — review and approve file writes, shell commands, and other actions before the agent executes them on your code
|
||||
|
||||
WHO IT'S FOR
|
||||
|
||||
• Developers who run opencode on their workstation or a server and want to check in from their phone
|
||||
• Engineers away from their desk who want to guide long-running AI coding sessions
|
||||
• Teams who self-host AI dev tools and want a polished mobile companion
|
||||
|
||||
WHAT IT IS NOT
|
||||
|
||||
• Not an AI model — you bring your own opencode server (which connects to Claude, GPT-4, Gemini, or local models via your API keys)
|
||||
• Not a code editor — pairs with your existing IDE and terminal workflow
|
||||
• Not a subscription service — the app is free and open source
|
||||
|
||||
OPEN SOURCE
|
||||
|
||||
OpenCode Mobile is MIT licensed. Source code, issue tracker, and community discussion:
|
||||
https://github.com/dzianisv/opencode-mobile
|
||||
|
||||
PRIVACY
|
||||
|
||||
OpenCode Mobile does not collect your code, prompts, or AI responses. All AI traffic goes directly from the app to YOUR opencode server — never through our infrastructure. We use Sentry for crash reporting only (no personally identifiable information, no message content). See our privacy policy for full details.
|
||||
|
||||
SELF-HOSTED FIRST
|
||||
|
||||
OpenCode requires you to run an opencode server:
|
||||
1. Install: npm install -g opencode-ai
|
||||
2. Run: opencode serve
|
||||
3. Connect the app to the server URL
|
||||
|
||||
If you cannot self-host, contact support@vibebrowser.app and we will provide a temporary review endpoint.
|
||||
|
||||
SUPPORT
|
||||
|
||||
Email: support@vibebrowser.app
|
||||
Issues: https://github.com/dzianisv/opencode-mobile/issues
|
||||
```
|
||||
|
||||
(Character count: ~1,750 — well under 4,000 limit. Add more feature detail or FAQ if desired.)
|
||||
|
||||
---
|
||||
|
||||
## Keywords (max 100 chars, comma-separated)
|
||||
|
||||
```
|
||||
opencode,AI coding,developer,LLM,Claude,GPT,coding agent,self-hosted,mobile dev,terminal
|
||||
```
|
||||
(89 chars)
|
||||
|
||||
Alternative / supplemental terms to rotate in A/B: `code review`, `AI assistant`, `remote dev`, `SSH`, `copilot`
|
||||
|
||||
---
|
||||
|
||||
## URLs
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Support URL | https://www.vibebrowser.app/ |
|
||||
| Marketing URL | https://github.com/dzianisv/opencode-mobile |
|
||||
| Privacy Policy URL | https://opencode.vibebrowser.app/privacy |
|
||||
|
||||
---
|
||||
|
||||
## App Category
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Primary Category | Developer Tools |
|
||||
| Secondary Category | Productivity |
|
||||
|
||||
---
|
||||
|
||||
## Pricing & Availability
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Price | Free |
|
||||
| In-App Purchases | None |
|
||||
| Availability | All territories (no regional restrictions) |
|
||||
|
||||
---
|
||||
|
||||
## Age Rating Questionnaire
|
||||
|
||||
Apple uses a questionnaire to assign an age rating. Answer as follows for OpenCode Mobile:
|
||||
|
||||
| Question | Answer | Notes |
|
||||
|---|---|---|
|
||||
| Cartoon or fantasy violence | None | Dev tool — no violence content |
|
||||
| Realistic violence | None | |
|
||||
| Prolonged graphic violence | None | |
|
||||
| Sexual content or nudity | None | |
|
||||
| Profanity or crude humor | None | |
|
||||
| Mature or suggestive themes | None | |
|
||||
| Horror/fear-inducing content | None | |
|
||||
| Medical/treatment information | None | |
|
||||
| Alcohol, tobacco, drugs | None | |
|
||||
| Gambling | None | |
|
||||
| Contests | None | |
|
||||
| Unrestricted web access | No | App connects to user-specified servers only, no general browser |
|
||||
| Sharing location data | No | |
|
||||
| User-generated content | No | Chat is between user and their own AI backend, not user-to-user |
|
||||
|
||||
**Expected rating: 4+** (no objectionable content; developer tool)
|
||||
|
||||
---
|
||||
|
||||
## Privacy Nutrition Label (App Privacy)
|
||||
|
||||
Apple requires you to declare what data the app collects. Fill the App Privacy section in App Store Connect as follows.
|
||||
|
||||
### Data Not Collected
|
||||
|
||||
OpenCode Mobile does NOT collect any of the following:
|
||||
- Name, Email address, Phone number, Physical address, Other contact info
|
||||
- Health/fitness data
|
||||
- Financial info, payment info
|
||||
- Precise or coarse location
|
||||
- Contacts
|
||||
- Emails or text messages
|
||||
- Photos or videos
|
||||
- Audio data
|
||||
- Gameplay content
|
||||
- Customer support data
|
||||
- Browsing history, search history
|
||||
- Sensitive info
|
||||
- User content (code, prompts, AI responses are not sent to our servers)
|
||||
- Identifiers (User ID, Device ID — Sentry uses an installation-scoped anonymous ID, see below)
|
||||
|
||||
### Data Linked to You: None
|
||||
|
||||
### Data Not Linked to You
|
||||
|
||||
| Data Type | Category | Purpose | Optional? |
|
||||
|---|---|---|---|
|
||||
| Crash Data | Diagnostics | App functionality | No — always on (see note) |
|
||||
| Performance Data | Diagnostics | App functionality | No — always on (see note) |
|
||||
| Other Diagnostic Data | Diagnostics | App functionality | No |
|
||||
|
||||
**Explanation**: Sentry crash reporting sends device model, OS version, app version, and stack traces. Sentry assigns an anonymous installation ID (not linked to any Apple ID or personal information). No user-generated content (code, prompts, responses) is ever sent.
|
||||
|
||||
**Sentry opt-in status**: As of v0.2.3, Sentry is **always on** when a DSN is configured. If you add a settings toggle for Sentry consent (planned), change Optional? to "Yes" and add a note that users who decline are in the "Data Not Collected" category. In App Store Connect, once opt-in is implemented, this section can be removed or marked optional.
|
||||
|
||||
**"Are you or your third-party partners using this data to track users?"**: No
|
||||
|
||||
**App Tracking Transparency (ATT)**: OpenCode Mobile does **not** use the ATT framework (`AppTrackingTransparency`) and does **not** access the IDFA (Identifier for Advertisers). No ad networks or cross-app tracking SDKs are present. No ATT permission prompt is shown to users.
|
||||
|
||||
---
|
||||
|
||||
## Export Compliance
|
||||
|
||||
Apple asks about encryption during submission. Answer:
|
||||
|
||||
| Question | Answer |
|
||||
|---|---|
|
||||
| Does the app use encryption beyond what is in the operating system? | No |
|
||||
| Does the app qualify for any exemptions? | N/A |
|
||||
|
||||
**Rationale**: OpenCode Mobile uses only standard HTTPS/TLS provided by iOS networking APIs (URLSession via React Native's fetch). It does not implement any custom cryptographic algorithms. Per US Export Administration Regulations (EAR), apps using only standard OS-provided encryption and that do not modify the encryption are exempt from ERN requirements. Source: https://developer.apple.com/documentation/security/complying_with_encryption_export_regulations
|
||||
|
||||
**Action**: In App Store Connect > App Information > Export Compliance, select "No" when asked if the app uses non-exempt encryption.
|
||||
|
||||
---
|
||||
|
||||
## App Review Notes — ATS Justification
|
||||
|
||||
The app's `Info.plist` sets `NSAllowsArbitraryLoads: true` in `NSAppTransportSecurity`. Apple App Store review may ask for justification. Paste the following in the **App Review Notes** field in App Store Connect, or in the reviewer communication:
|
||||
|
||||
---
|
||||
|
||||
**Justification for NSAllowsArbitraryLoads:**
|
||||
|
||||
OpenCode is a developer tool that connects to user-self-hosted opencode CLI servers. These servers typically run on `localhost` or a LAN address (e.g. `http://192.168.1.100:4096`) over plain HTTP. Requiring TLS would prevent the app from functioning as designed for the dev-tool use case, because:
|
||||
|
||||
1. The opencode server (`opencode serve`) serves over plain HTTP by default. Requiring the user to configure TLS certificates for a localhost developer tool is an unreasonable burden.
|
||||
2. The connection targets are the user's **own** machines, not third-party services. There is no user-to-user data exchange and no third-party server communication through this code path.
|
||||
3. `NSAllowsArbitraryLoadsInWebContent` is explicitly set to `false` — we only relax ATS for the app's own network calls to the user-configured backend.
|
||||
|
||||
This is exactly the use case Apple's own documentation acknowledges when describing developer tools and enterprise apps that connect to custom internal servers. Reference: https://developer.apple.com/documentation/bundleresources/information_property_list/nsapptransportsecurity
|
||||
|
||||
We do not weaken security for any user-facing content delivered by third parties. If the reviewer requires additional justification or a demonstration, we are happy to provide a screen recording or a live server endpoint.
|
||||
|
||||
---
|
||||
|
||||
## App Review Information
|
||||
|
||||
### Sign-in Required
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Sign-in required? | No — the app does not have user accounts |
|
||||
|
||||
### App Access Notes
|
||||
|
||||
Paste the following in the "Notes" field of the App Review Information section:
|
||||
|
||||
```
|
||||
OpenCode Mobile requires the reviewer to connect to an opencode server.
|
||||
|
||||
OPTION A — We provide a hosted review endpoint:
|
||||
Contact support@vibebrowser.app before the review window and we will email a temporary server URL valid for 72 hours.
|
||||
|
||||
OPTION B — Self-host (5 minutes):
|
||||
1. Install Node.js 20+ on any macOS/Linux machine
|
||||
2. Run: npm install -g opencode-ai
|
||||
3. Run: opencode serve --hostname 0.0.0.0
|
||||
4. The terminal prints a URL like: http://192.168.x.x:4096
|
||||
5. In the app: tap "Add Connection" → enter that URL → tap "Connect"
|
||||
6. Tap "New Session" → type any prompt (e.g. "list files in current directory")
|
||||
7. Observe streaming response and tool call approval flow
|
||||
|
||||
Note: The --hostname 0.0.0.0 flag makes the server listen on all interfaces
|
||||
so the iOS device (or simulator) on the same Wi-Fi network can reach it.
|
||||
Without it, the server only accepts connections from localhost.
|
||||
|
||||
The app has no hidden features or paywalls. All functionality is accessible after connecting to a server.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Graphic Assets — Required Before Submission
|
||||
|
||||
All icons and screenshots must be provided before submitting for review.
|
||||
|
||||
### App Icon
|
||||
|
||||
| Asset | Size | Format | Notes |
|
||||
|---|---|---|---|
|
||||
| App Icon | 1024×1024 px | PNG, no alpha channel | Used for App Store; Xcode fans out all other sizes |
|
||||
|
||||
The 1024×1024 icon must NOT have rounded corners (Apple applies them). No transparency.
|
||||
|
||||
Current status: `assets/icon.json` is a placeholder — **real PNG required before submission**.
|
||||
|
||||
### iPhone Screenshots (REQUIRED)
|
||||
|
||||
Minimum 1 screenshot per device class. Recommended: 3–5 showing key flows.
|
||||
|
||||
| Device | Resolution | Size name in App Store Connect |
|
||||
|---|---|---|
|
||||
| iPhone 6.7" (iPhone 16 Pro Max / 15 Plus) | 1320×2868 or 1290×2796 | 6.7" Super Retina XDR Display |
|
||||
| iPhone 6.5" (iPhone 14 Plus / 11 Pro Max) | 1242×2688 | 6.5" Super Retina XDR Display |
|
||||
| iPhone 5.5" (iPhone 8 Plus) | 1242×2208 | 5.5" Retina HD Display |
|
||||
|
||||
Note: As of 2024, Apple only requires 6.7" and 6.5" for new submissions. 5.5" is optional but recommended for coverage.
|
||||
|
||||
Suggested screenshot subjects:
|
||||
1. Connection setup screen (add server URL)
|
||||
2. Active chat session — streaming AI response
|
||||
3. File diff view — seeing a code change
|
||||
4. Tool approval dialog
|
||||
5. Session list / multi-session view
|
||||
6. Biometric unlock (if possible to screenshot without triggering auth)
|
||||
|
||||
### iPad Screenshots (REQUIRED for Universal apps)
|
||||
|
||||
Since `supportsTablet: true`, iPad screenshots are required.
|
||||
|
||||
| Device | Resolution | Size name in App Store Connect |
|
||||
|---|---|---|
|
||||
| iPad 12.9" (iPad Pro 6th gen) | 2048×2732 | 12.9" iPad Pro (6th gen) |
|
||||
| iPad 11" (iPad Pro M4) | 1668×2388 | 11" iPad Pro (M4) |
|
||||
|
||||
Minimum 1 per device class required. iPad screenshots can be the same content as iPhone.
|
||||
|
||||
### Preview Videos (Optional)
|
||||
|
||||
- Max 30 seconds
|
||||
- Same resolution as screenshots for each device class
|
||||
- MP4 or MOV
|
||||
- No audio required
|
||||
|
||||
---
|
||||
|
||||
## TestFlight Beta App Description (shown to TestFlight testers)
|
||||
|
||||
```
|
||||
OpenCode Mobile — iOS beta
|
||||
|
||||
Drive your self-hosted opencode AI coding agent from your iPhone or iPad. Connect to opencode running on your workstation (or any server) and guide AI coding sessions remotely.
|
||||
|
||||
This is an early beta. Please report issues via the TestFlight feedback button or email support@vibebrowser.app.
|
||||
|
||||
To use: you need opencode running somewhere accessible (local Wi-Fi, Tailscale, Cloudflare Tunnel, etc). Run `opencode serve` and enter the server URL in the app.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pending Before First Submission
|
||||
|
||||
- [ ] Apple Developer Program enrollment approved (D-U-N-S 142059652, VIBE TECHNOLOGIES LLC)
|
||||
- [ ] App Store Connect app record created (bundle ID: ai.opencode.mobile)
|
||||
- [ ] App icon 1024×1024 PNG (no alpha, no rounded corners)
|
||||
- [ ] iPhone screenshots (6.7" minimum; 6.5" strongly recommended)
|
||||
- [ ] iPad screenshots (12.9" minimum)
|
||||
- [ ] Privacy policy live at https://opencode.vibebrowser.app/privacy
|
||||
- [ ] App Store Connect API key created (for CI — Key ID, Issuer ID, .p8 file)
|
||||
- [ ] Apple Distribution certificate + provisioning profile (or use EAS managed signing)
|
||||
- [ ] Export compliance answered (No to custom encryption)
|
||||
- [ ] App privacy nutrition label filled
|
||||
- [ ] Age rating questionnaire completed (expected: 4+)
|
||||
- [ ] TestFlight internal group created
|
||||
- [ ] Review notes prepared with temporary server URL or self-host instructions
|
||||
137
distribution/fdroid-submission/REPRODUCIBLE-BUILD-NOTES.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# Reproducible Build Notes — ai.opencode.mobile
|
||||
|
||||
F-Droid's modern `AllowedAPKSigningKeys` path requires that F-Droid's build
|
||||
server can compile the same APK and arrive at a binary that matches the
|
||||
pre-signed APK we supply via GitHub releases. Any non-determinism in the build
|
||||
will break this verification.
|
||||
|
||||
---
|
||||
|
||||
## Issues found (2026-05-24)
|
||||
|
||||
### 1. Kotlin error log files tracked in git — MEDIUM
|
||||
|
||||
**Files committed:**
|
||||
```
|
||||
android/.kotlin/errors/errors-1779181311003.log
|
||||
android/.kotlin/errors/errors-1779181311094.log
|
||||
```
|
||||
|
||||
**Problem:** These log files contain absolute host paths:
|
||||
```
|
||||
While analysing /home/azureuser/workspace/opencode-mobile/node_modules/...
|
||||
```
|
||||
|
||||
When F-Droid builds from source on their server, these log files will not
|
||||
exist (or will contain different paths). Since they are tracked in git and
|
||||
checked out during the build, they could cause differing build outputs
|
||||
if the Kotlin compiler reads or embeds them. More practically, they make
|
||||
the source tree non-portable — a smell that will draw reviewer attention.
|
||||
|
||||
**Recommended fix:** Add `.kotlin/` to `android/.gitignore`:
|
||||
```
|
||||
# android/.gitignore (add this line)
|
||||
.kotlin/
|
||||
```
|
||||
|
||||
Then remove the tracked files:
|
||||
```bash
|
||||
git rm -r --cached android/.kotlin/
|
||||
git commit -m "chore: untrack kotlin error log files from android/.kotlin/"
|
||||
```
|
||||
|
||||
This is a trivial fix. Do it before filing the F-Droid MR.
|
||||
|
||||
---
|
||||
|
||||
### 2. android/ directory tracked in git — LOW (expected but notable)
|
||||
|
||||
`expo prebuild` regenerates `android/` from `app.json` and `package.json`.
|
||||
F-Droid's build metadata uses `npx expo prebuild` as a `prebuild:` step,
|
||||
which means F-Droid rebuilds `android/` from scratch on their server.
|
||||
|
||||
The tracked `android/app/build.gradle` and other generated files must match
|
||||
what `expo prebuild` produces. If the Expo SDK version drifts between what is
|
||||
committed and what npm installs, the build will fail.
|
||||
|
||||
**Mitigation already in place:** `package-lock.json` is committed, which pins
|
||||
all npm dependency versions. The F-Droid metadata `Builds:` step uses
|
||||
`npm install --legacy-peer-deps` which respects `package-lock.json`.
|
||||
|
||||
**Residual risk:** If `expo prebuild` is non-deterministic (e.g., writes the
|
||||
current date/time into generated files), subsequent runs will produce different
|
||||
outputs. This is unlikely but should be verified by running prebuild twice and
|
||||
comparing outputs:
|
||||
```bash
|
||||
npx expo prebuild --platform android --non-interactive --clean
|
||||
git diff android/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Hermes bytecode embedding — LOW
|
||||
|
||||
The React Native Hermes engine compiles the JavaScript bundle to Hermes bytecode
|
||||
at build time. The bytecode format is versioned but should be deterministic for
|
||||
the same JS source + Hermes version. The Hermes version is pinned via
|
||||
`react-native` in `package-lock.json`, so this is low risk.
|
||||
|
||||
---
|
||||
|
||||
### 4. PNG crunching — LOW
|
||||
|
||||
`build.gradle` has `crunchPngs true` for release builds. PNG crunching via aapt2
|
||||
is generally deterministic but can vary across aapt2 versions. F-Droid's build
|
||||
environment may use a different Android build tools version.
|
||||
|
||||
**Mitigation:** Pin `buildToolsVersion` in `android/build.gradle` explicitly
|
||||
rather than relying on the Expo-supplied default. Check via:
|
||||
```bash
|
||||
grep buildToolsVersion android/build.gradle android/app/build.gradle
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. No hardcoded timestamps found — PASS
|
||||
|
||||
Grepped `android/` for `System.currentTimeMillis`, `new Date()`, `buildTime`,
|
||||
`BUILD_DATE`, `UUID.randomUUID()` — no results. This is the most common
|
||||
reproducibility killer and is clean here.
|
||||
|
||||
---
|
||||
|
||||
### 6. No absolute host paths in build files — PASS
|
||||
|
||||
Grepped `android/` `*.gradle` and `*.properties` for `/home/`, `/Users/`,
|
||||
`C:\` — no results in build config files.
|
||||
|
||||
---
|
||||
|
||||
## Priority action items before F-Droid MR
|
||||
|
||||
| Priority | Item | Effort |
|
||||
|----------|------|--------|
|
||||
| HIGH | Add `.kotlin/` to `android/.gitignore` and untrack log files | 5 min |
|
||||
| MEDIUM | Run `expo prebuild` twice, compare output with `git diff` | 15 min |
|
||||
| MEDIUM | Pin `buildToolsVersion` explicitly in `android/build.gradle` | 5 min |
|
||||
| LOW | Verify Hermes bytecode is deterministic (compare two builds) | 30 min |
|
||||
| LOW | Test full reproducible build using F-Droid's Docker build env | Hours |
|
||||
|
||||
---
|
||||
|
||||
## How to test reproducible builds
|
||||
|
||||
F-Droid provides a reproducible build test tool:
|
||||
|
||||
```bash
|
||||
# Install fdroidserver
|
||||
pip install fdroidserver
|
||||
|
||||
# Test reproducibility against a released APK
|
||||
fdroid signatures path/to/app-release.apk
|
||||
|
||||
# Full build test
|
||||
fdroid build ai.opencode.mobile:<versionCode> --verbose
|
||||
```
|
||||
|
||||
See https://f-droid.org/en/docs/Reproducible_Builds/ for the full guide.
|
||||
163
distribution/fdroid-submission/SIZE-OPTIMIZATION.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# APK Size Optimization for F-Droid / IzzyOnDroid
|
||||
|
||||
## Current state
|
||||
|
||||
| Artifact | Size |
|
||||
|----------|------|
|
||||
| Universal AAB (`app-release.aab`) | 58.5 MB |
|
||||
| Per-ABI APK (estimated) | ~20–25 MB |
|
||||
| IzzyOnDroid per-APK limit | 30 MB |
|
||||
|
||||
`bundletool` is not installed in this environment, so per-ABI APK sizes were not
|
||||
measured directly. The estimate above is based on typical Expo/Hermes React Native
|
||||
apps:
|
||||
- Hermes JS engine binary: ~8–10 MB per ABI
|
||||
- React Native native libraries: ~5–8 MB per ABI
|
||||
- JavaScript bundle (ABI-independent): ~6–8 MB
|
||||
- Assets (icons, splash, etc.): ~2–3 MB
|
||||
|
||||
**Conclusion:** arm64-v8a APK is likely ~20–25 MB — within IzzyOnDroid's 30 MB limit.
|
||||
No ABI splits required for the initial submission.
|
||||
|
||||
To verify when bundletool is available:
|
||||
```bash
|
||||
bundletool build-apks \
|
||||
--bundle=android/app/build/outputs/bundle/release/app-release.aab \
|
||||
--output=apks.apks \
|
||||
--mode=universal
|
||||
|
||||
# For per-ABI sizes:
|
||||
bundletool build-apks \
|
||||
--bundle=android/app/build/outputs/bundle/release/app-release.aab \
|
||||
--output=apks-splits.apks \
|
||||
--mode=default
|
||||
|
||||
unzip apks-splits.apks -d apk-splits/
|
||||
ls -lh apk-splits/splits/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## If arm64-v8a APK exceeds 30 MB — fix approach
|
||||
|
||||
### Option A: ABI splits in Expo config plugin (recommended)
|
||||
|
||||
`android/app/build.gradle` is regenerated by `npx expo prebuild` on every CI run,
|
||||
so direct edits are overwritten. The correct approach is an Expo config plugin.
|
||||
|
||||
Create `plugins/withAbiSplits.js`:
|
||||
|
||||
```js
|
||||
const { withAppBuildGradle } = require('@expo/config-plugins');
|
||||
|
||||
module.exports = function withAbiSplits(config) {
|
||||
return withAppBuildGradle(config, (config) => {
|
||||
const contents = config.modResults.contents;
|
||||
// Insert splits block inside android { ... } after defaultConfig
|
||||
if (!contents.includes('splits {')) {
|
||||
config.modResults.contents = contents.replace(
|
||||
/defaultConfig \{/,
|
||||
`splits {
|
||||
abi {
|
||||
reset()
|
||||
enable true
|
||||
universalApk true
|
||||
include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||
}
|
||||
}
|
||||
defaultConfig {`
|
||||
);
|
||||
}
|
||||
return config;
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
Register in `app.json`:
|
||||
```json
|
||||
{
|
||||
"expo": {
|
||||
"plugins": [
|
||||
"./plugins/withAbiSplits.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After `npx expo prebuild`, `android/app/build.gradle` will contain the splits block.
|
||||
Run `./gradlew assembleRelease` — produces separate APKs per ABI.
|
||||
|
||||
For IzzyOnDroid / F-Droid: attach `app-arm64-v8a-release.apk` to the GitHub release.
|
||||
|
||||
### Option B: fdroid Gradle product flavor
|
||||
|
||||
Add a `fdroid` flavor that includes only arm64-v8a:
|
||||
|
||||
```groovy
|
||||
// In the config plugin or directly in build.gradle (pre-prebuild override)
|
||||
android {
|
||||
flavorDimensions "distribution"
|
||||
productFlavors {
|
||||
fdroid {
|
||||
dimension "distribution"
|
||||
ndk {
|
||||
abiFilters "arm64-v8a"
|
||||
}
|
||||
}
|
||||
play {
|
||||
dimension "distribution"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Build with: `./gradlew assembleFdroidRelease`
|
||||
|
||||
This also provides a clean hook for excluding FCM artifacts (see below).
|
||||
|
||||
---
|
||||
|
||||
## FCM / expo-notifications
|
||||
|
||||
`expo-notifications` compiles FCM receiver classes even when only local
|
||||
notifications are used (the app only calls `scheduleNotificationAsync` — no
|
||||
push token retrieval). F-Droid scanner may flag `com.google.firebase:firebase-messaging`
|
||||
as `NonFreeNet` or `NonFreeDep`.
|
||||
|
||||
**Mitigation for F-Droid mainline:** add a `fdroid` product flavor that
|
||||
excludes the FCM artifact:
|
||||
|
||||
```groovy
|
||||
// In config plugin
|
||||
android {
|
||||
flavorDimensions "distribution"
|
||||
productFlavors {
|
||||
fdroid {
|
||||
dimension "distribution"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configurations.fdroidImplementation {
|
||||
exclude group: 'com.google.firebase', module: 'firebase-messaging'
|
||||
}
|
||||
```
|
||||
|
||||
Or patch `expo-notifications` `build.gradle` via a Gradle init script to
|
||||
replace the FCM dependency with a no-op stub in the `fdroid` flavor.
|
||||
|
||||
**This is not required for IzzyOnDroid** (more tolerant of GMS dependencies
|
||||
if they are not actively invoked). Track the F-Droid reviewer's feedback
|
||||
before investing in this fix — they may accept without it given the
|
||||
local-only usage.
|
||||
|
||||
---
|
||||
|
||||
## Action items (when ready to optimize)
|
||||
|
||||
1. Install bundletool: `sudo apt-get install bundletool` or download JAR from
|
||||
https://github.com/google/bundletool/releases
|
||||
2. Run `build-apks --mode=default` to measure per-ABI sizes
|
||||
3. If arm64-v8a > 30 MB: implement config plugin (Option A above)
|
||||
4. For F-Droid mainline FCM concern: implement `fdroid` product flavor (Option B)
|
||||
5. Document measured sizes in this file once known
|
||||
153
distribution/fdroid-submission/SUBMISSION-CHECKLIST.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# F-Droid Mainline Submission Checklist
|
||||
|
||||
This checklist covers the steps to file a Merge Request against
|
||||
https://gitlab.com/fdroid/fdroiddata to add `ai.opencode.mobile` to the
|
||||
F-Droid main repository.
|
||||
|
||||
**Do NOT start this process until ALL prerequisites are checked.**
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites (must all be true before filing)
|
||||
|
||||
- [ ] First Google Play release is live (proves signing key is in production use)
|
||||
- [ ] Signed APK (not AAB) is attached to a GitHub release tag (e.g. `v0.2.4`)
|
||||
- [ ] Sentry opt-in gate is merged to `main` (avoids `Tracking` anti-feature)
|
||||
- [ ] `expo-notifications` FCM-free flavor exists OR F-Droid team has been pre-warned
|
||||
(see `SIZE-OPTIMIZATION.md` section "FCM Flavor")
|
||||
- [ ] Signing key SHA-256 fingerprint is confirmed in `distribution/SIGNING-KEY-FINGERPRINTS.md`
|
||||
- [ ] Reproducible build has been tested locally (see `REPRODUCIBLE-BUILD-NOTES.md`)
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — Prepare the signing key fingerprint
|
||||
|
||||
```bash
|
||||
# Get the colon-separated fingerprint
|
||||
keytool -list -v \
|
||||
-keystore keystores/production-release.jks \
|
||||
-storepass <STOREPASS> \
|
||||
| grep "SHA256:"
|
||||
# Example output:
|
||||
# SHA256: 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
|
||||
|
||||
# Convert to lowercase without colons (AllowedAPKSigningKeys format):
|
||||
# 0c259d94e0ffea5d6319614b229d4b6bdc22de1f56e38e769483 98d2df6aa099
|
||||
```
|
||||
|
||||
Update `distribution/fdroid-submission/metadata.yml`:
|
||||
- Replace `<SIGNING_KEY_SHA256_FINGERPRINT_LOWERCASE_NO_COLONS>` with the fingerprint
|
||||
- Replace `<FIRST_GITHUB_RELEASE_TAG>` with the actual tag (e.g. `v0.2.4`)
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — Fork fdroiddata
|
||||
|
||||
```bash
|
||||
# On GitLab
|
||||
# 1. Go to https://gitlab.com/fdroid/fdroiddata
|
||||
# 2. Fork to your personal GitLab account (not org — fdroid prefers personal forks)
|
||||
# 3. Clone locally:
|
||||
git clone https://gitlab.com/<YOUR_GITLAB_USERNAME>/fdroiddata.git
|
||||
cd fdroiddata
|
||||
git remote add upstream https://gitlab.com/fdroid/fdroiddata.git
|
||||
git fetch upstream
|
||||
git checkout -b add-ai.opencode.mobile upstream/master
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — Add the metadata file
|
||||
|
||||
```bash
|
||||
cp /path/to/opencode-mobile/distribution/fdroid-submission/metadata.yml \
|
||||
metadata/ai.opencode.mobile.yml
|
||||
```
|
||||
|
||||
Verify:
|
||||
- `metadata/ai.opencode.mobile.yml` exists
|
||||
- `AllowedAPKSigningKeys` has the correct lowercase-no-colons fingerprint
|
||||
- `commit:` points to a real tag in the GitHub repo
|
||||
- `versionCode` and `versionName` match the APK attached to the release
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — Test the build locally (optional but strongly recommended)
|
||||
|
||||
F-Droid provides a Docker-based build environment:
|
||||
|
||||
```bash
|
||||
# Install fdroidserver
|
||||
pip install fdroidserver
|
||||
|
||||
# Verify metadata parses cleanly
|
||||
fdroid readmeta
|
||||
|
||||
# Attempt a build (requires Docker + significant time)
|
||||
fdroid build ai.opencode.mobile:<versionCode>
|
||||
```
|
||||
|
||||
If the build fails, fix `metadata/ai.opencode.mobile.yml` before filing the MR.
|
||||
|
||||
---
|
||||
|
||||
## Step 5 — File the Merge Request
|
||||
|
||||
```bash
|
||||
git add metadata/ai.opencode.mobile.yml
|
||||
git commit -m "Add ai.opencode.mobile (OpenCode Mobile)"
|
||||
git push origin add-ai.opencode.mobile
|
||||
```
|
||||
|
||||
Go to https://gitlab.com/<YOUR_GITLAB_USERNAME>/fdroiddata → open an MR
|
||||
against `fdroid/fdroiddata:master`.
|
||||
|
||||
MR title: `Add ai.opencode.mobile`
|
||||
|
||||
MR description template:
|
||||
```
|
||||
## New app: OpenCode Mobile
|
||||
|
||||
**Package:** ai.opencode.mobile
|
||||
**License:** MIT
|
||||
**Category:** Development
|
||||
**Source:** https://github.com/dzianisv/opencode-mobile
|
||||
|
||||
OpenCode Mobile is a free, open-source mobile client for the opencode AI
|
||||
coding agent (sst/opencode). MIT licensed. Crash reporting opt-in default OFF.
|
||||
|
||||
Anti-features: NonFreeNet (user-self-hosted backend may connect to proprietary AI APIs).
|
||||
|
||||
Using AllowedAPKSigningKeys path — pre-signed APK from GitHub releases.
|
||||
Build steps: npm install → expo prebuild → Gradle assembleRelease.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 6 — Respond to reviewer feedback
|
||||
|
||||
- F-Droid maintainers typically review within 2–8 weeks.
|
||||
- Monitor the MR for comments. Common asks:
|
||||
- Build reproducibility evidence
|
||||
- Clarification on anti-features
|
||||
- Pinning build dependencies to exact versions
|
||||
- Removing or stubbing FCM/GMS dependencies
|
||||
|
||||
---
|
||||
|
||||
## Step 7 — After acceptance
|
||||
|
||||
- F-Droid builds from source on their CI. First index update may take 1–2 weeks.
|
||||
- Add `ai.opencode.mobile` to F-Droid's inclusion notice in `docs/fdroid.md`.
|
||||
- Update `distribution/strategy.md` status row for F-Droid.
|
||||
- Notify IzzyOnDroid via the inclusion issue that mainline accepted the app
|
||||
(IzzyOnDroid will then auto-delist within their next index rebuild).
|
||||
|
||||
---
|
||||
|
||||
## Reference
|
||||
|
||||
- F-Droid inclusion criteria: https://f-droid.org/en/docs/Inclusion_Policy/
|
||||
- F-Droid metadata format: https://f-droid.org/en/docs/Build_Metadata_Reference/
|
||||
- AllowedAPKSigningKeys: https://f-droid.org/en/docs/Reproducible_Builds/
|
||||
- fdroiddata: https://gitlab.com/fdroid/fdroiddata
|
||||
107
distribution/fdroid-submission/metadata.yml
Normal file
@@ -0,0 +1,107 @@
|
||||
# F-Droid metadata for ai.opencode.mobile
|
||||
# Target file path in fdroiddata: metadata/ai.opencode.mobile.yml
|
||||
#
|
||||
# BEFORE FILING THE MR:
|
||||
# 1. Replace <SIGNING_KEY_SHA256_FINGERPRINT> with the actual colon-separated hex fingerprint
|
||||
# (found in distribution/SIGNING-KEY-FINGERPRINTS.md)
|
||||
# 2. Replace <FIRST_GITHUB_RELEASE_TAG> with the first tag that has a signed APK attached
|
||||
# (e.g. v0.2.4)
|
||||
# 3. Verify the build steps produce a matching APK against AllowedAPKSigningKeys
|
||||
#
|
||||
# Do NOT file this MR until:
|
||||
# - First Google Play release is live (establishes signing key in production use)
|
||||
# - Sentry opt-in gate is merged to main (anti-feature Tracking avoided)
|
||||
# - You have the exact colon-separated SHA-256 key fingerprint confirmed
|
||||
|
||||
Categories:
|
||||
- Development
|
||||
|
||||
License: MIT
|
||||
|
||||
AuthorName: VIBE TECHNOLOGIES, LLC
|
||||
AuthorEmail: support@vibebrowser.app
|
||||
|
||||
WebSite: https://opencode.vibebrowser.app
|
||||
SourceCode: https://github.com/dzianisv/opencode-mobile
|
||||
IssueTracker: https://github.com/dzianisv/opencode-mobile/issues
|
||||
Changelog: https://github.com/dzianisv/opencode-mobile/releases
|
||||
|
||||
Summary: Drive your self-hosted AI coding agent from your phone
|
||||
|
||||
Description: |-
|
||||
OpenCode Mobile is a free, open-source (MIT) client for the opencode AI coding
|
||||
agent (sst/opencode). Connect to your self-hosted opencode server and drive
|
||||
AI-powered coding sessions from your phone — no proprietary backend, no mandatory
|
||||
accounts, no tracking by default.
|
||||
|
||||
'''Key features'''
|
||||
|
||||
* Multiple connection types — local network, secure tunnels (Cloudflare, ngrok),
|
||||
or any self-hosted opencode instance
|
||||
* Biometric unlock — fingerprint / PIN to keep your sessions private
|
||||
* Real-time streaming chat — watch your AI agent think and respond live
|
||||
* File diff viewer — see exactly what code changes the agent proposes
|
||||
* Multi-session management — start, resume, and switch between coding sessions
|
||||
* Tool call approval — review and approve agent actions before they run
|
||||
|
||||
'''Self-hosted first'''
|
||||
|
||||
The app requires your own opencode server. Your AI traffic goes directly to your
|
||||
backend (Claude, GPT, Gemini, local models — your choice). No middleman required.
|
||||
|
||||
An optional hosted backend ("opencode Cloud") is planned as a future paid service,
|
||||
but the client is always free and fully functional without it.
|
||||
|
||||
'''Crash reporting'''
|
||||
|
||||
Sentry crash reporting is opt-in with default OFF. Code, prompts, and AI responses
|
||||
never leave your own server.
|
||||
|
||||
'''Anti-features'''
|
||||
|
||||
NonFreeNet: the opencode server you connect to may connect to proprietary AI
|
||||
services (OpenAI, Anthropic, Google). The app itself contains no proprietary
|
||||
network code.
|
||||
|
||||
AntiFeatures:
|
||||
NonFreeNet:
|
||||
en-US: >-
|
||||
The app connects to a user-self-hosted opencode server which may in turn
|
||||
connect to proprietary AI services (OpenAI API, Anthropic API, Google Gemini).
|
||||
The app itself is fully open source and does not require any specific provider.
|
||||
|
||||
RepoType: git
|
||||
Repo: https://github.com/dzianisv/opencode-mobile
|
||||
|
||||
Builds:
|
||||
- versionName: '1.0.0'
|
||||
versionCode: 1
|
||||
commit: <FIRST_GITHUB_RELEASE_TAG>
|
||||
subdir: android
|
||||
sudo:
|
||||
- apt-get update
|
||||
- apt-get install -y nodejs npm
|
||||
init:
|
||||
- npm install --prefix .. --legacy-peer-deps
|
||||
- npx --prefix .. expo prebuild --platform android --non-interactive
|
||||
gradle:
|
||||
- release
|
||||
ndk: 26.1.10909125
|
||||
# Node 20+ required for Expo SDK 52+
|
||||
# prebuild regenerates android/ from app.json + package.json
|
||||
# The signed AAB/APK is then compared against AllowedAPKSigningKeys
|
||||
prebuild:
|
||||
- cd .. && npm install --legacy-peer-deps
|
||||
- cd .. && npx expo prebuild --platform android --non-interactive
|
||||
|
||||
# AllowedAPKSigningKeys pins our release signing key.
|
||||
# F-Droid will serve our pre-signed APK rather than re-signing with their key.
|
||||
# This requires reproducible builds (identical output across machines).
|
||||
AllowedAPKSigningKeys: <SIGNING_KEY_SHA256_FINGERPRINT_LOWERCASE_NO_COLONS>
|
||||
|
||||
AutoUpdateMode: Version v%v
|
||||
UpdateCheckMode: Tags
|
||||
UpdateCheckData: https://raw.githubusercontent.com/dzianisv/opencode-mobile/main/app.json|"version":\s*"([^"]+)"|.|.
|
||||
|
||||
CurrentVersion: '1.0.0'
|
||||
CurrentVersionCode: 1
|
||||
173
distribution/ios-enrollment-runbook.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# Apple Developer Program Enrollment Runbook — VIBE TECHNOLOGIES, LLC
|
||||
|
||||
Pre-filled guide for enrolling as an organization. Do NOT proceed until you have $99 USD available on the Apple ID credit card, and you have the governor's contact information ready for the verification call.
|
||||
|
||||
Reference: https://developer.apple.com/programs/enroll/
|
||||
|
||||
---
|
||||
|
||||
## Pre-filled Entity Data
|
||||
|
||||
| Field | Value | Source |
|
||||
|---|---|---|
|
||||
| Legal Entity Name | VIBE TECHNOLOGIES, LLC | WA LLC registration |
|
||||
| D-U-N-S Number | **142059652** | Already retrieved |
|
||||
| UBI / EIN | 606 003 933 | WA Secretary of State |
|
||||
| Legal Address | 519 S Henderson St, Seattle WA 98108-4522, USA | WA LLC registration |
|
||||
| Legal Entity Type | LLC (Limited Liability Company) | |
|
||||
| Primary Contact / Authorized Agent | Dzianis Vashchuk | Governor of LLC |
|
||||
| Primary Contact Phone | (use a number reachable for Apple's verification call) | |
|
||||
| Primary Contact Email | support@vibebrowser.app | |
|
||||
| Website | https://www.vibebrowser.app/ | |
|
||||
|
||||
---
|
||||
|
||||
## Apple ID to Use
|
||||
|
||||
**DECIDED 2026-05-24**: Use `support@vibebrowser.app` — mailbox already exists (was verified during Play Console signup, confirmed receiving Google verification codes).
|
||||
|
||||
- If no Apple ID exists yet for `support@vibebrowser.app`: create at https://appleid.apple.com/account
|
||||
- 2FA: enable immediately, trusted phone = Dzianis's mobile
|
||||
- Bitwarden item naming: store as `APPLE_ID_VIBE_TECHNOLOGIES` (email + password + 2FA recovery codes)
|
||||
|
||||
---
|
||||
|
||||
## Step-by-Step Enrollment
|
||||
|
||||
### Step 1 — Prepare
|
||||
|
||||
- [ ] Verify D-U-N-S 142059652 is current at https://developer.apple.com/enroll/duns-lookup/ (takes 14 days to propagate if recently created; ours was already retrieved so should be active)
|
||||
- [ ] Ensure the Apple ID email mailbox is active and accessible
|
||||
- [ ] Have a credit card ready ($99 USD charge)
|
||||
- [ ] Ensure Dzianis Vashchuk is available for a verification phone call during business hours (Apple calls the listed phone number for organization enrollment)
|
||||
|
||||
### Step 2 — Start Enrollment
|
||||
|
||||
1. Go to https://developer.apple.com/programs/enroll/
|
||||
2. Click **Start Your Enrollment**
|
||||
3. Sign in with the Apple ID you chose above (or create one)
|
||||
4. Select **Company / Organization**
|
||||
|
||||
### Step 3 — Enter Organization Details
|
||||
|
||||
Fill as follows:
|
||||
|
||||
| Prompt | Enter |
|
||||
|---|---|
|
||||
| Legal Entity Name | `VIBE TECHNOLOGIES, LLC` |
|
||||
| D-U-N-S Number | `142059652` |
|
||||
| Headquarters Address (Line 1) | `519 S Henderson St` |
|
||||
| City | `Seattle` |
|
||||
| State | `WA` |
|
||||
| ZIP | `98108` |
|
||||
| Country | `United States` |
|
||||
| Phone | (Dzianis's direct mobile — Apple calls this) |
|
||||
| Website | `https://www.vibebrowser.app/` |
|
||||
|
||||
### Step 4 — Verify Your Authority
|
||||
|
||||
Apple asks you to confirm you are authorized to bind the organization to the Apple Developer Program Agreement. As governor/managing member of the LLC, Dzianis Vashchuk has this authority.
|
||||
|
||||
Select: "I am authorized to sign legal agreements on behalf of this organization."
|
||||
|
||||
### Step 5 — Apple Review & Verification Call
|
||||
|
||||
- Apple's team will verify the D-U-N-S number against Dun & Bradstreet records.
|
||||
- **Expect a phone call** to the number entered above within 2–5 business days.
|
||||
- The caller will confirm the legal entity name, address, and that you are authorized to enroll.
|
||||
- Answer in English; have the LLC registration handy (UBI 606 003 933) in case they ask for additional verification.
|
||||
|
||||
**Timeline**: 2–7 business days for verification. Apple can take up to 14 days in edge cases.
|
||||
|
||||
### Step 6 — Pay
|
||||
|
||||
After verification is approved:
|
||||
- Apple charges **$99 USD/year** to the credit card on the Apple ID.
|
||||
- Enrollment renews annually. Set a calendar reminder.
|
||||
- Source: https://developer.apple.com/support/enrollment/ (pricing as of 2025 — verify current pricing at enrollment time)
|
||||
|
||||
### Step 7 — Accept Agreements
|
||||
|
||||
After payment:
|
||||
1. Sign in to https://developer.apple.com/account/
|
||||
2. Accept the Apple Developer Program License Agreement
|
||||
3. Accept the Paid Applications Agreement (required to distribute free apps too)
|
||||
|
||||
### Step 8 — Set Up App Store Connect
|
||||
|
||||
1. Go to https://appstoreconnect.apple.com/
|
||||
2. Sign in with the same Apple ID
|
||||
3. Fill in banking info even for a free app (required to publish):
|
||||
- US bank account (ACH/routing number)
|
||||
- Tax information (W-9 for US entities — EIN 606 003 933)
|
||||
4. Accept the Paid Applications Schedule even if distributing free (Apple requires this)
|
||||
|
||||
---
|
||||
|
||||
## What Can Be Done in Parallel (Before Enrollment Approval)
|
||||
|
||||
While waiting for Apple's verification call and approval:
|
||||
|
||||
- [x] Prepare App Store listing copy → `distribution/app-store-listing.md`
|
||||
- [x] Write CI workflow (draft) → `.github/workflows/publish-app-store.yml`
|
||||
- [ ] Create app icon 1024×1024 PNG
|
||||
- [ ] Capture iPhone screenshots (use iOS Simulator in Xcode on any Mac)
|
||||
- [ ] Capture iPad screenshots
|
||||
- [ ] Write/publish privacy policy at https://www.vibebrowser.app/opencode-mobile/privacy
|
||||
- [ ] Set up EAS account at https://expo.dev/ (free tier, log in with Expo account)
|
||||
- [ ] Add iOS config patches to `app.json` (done in this PR)
|
||||
- [ ] Run `npx expo prebuild --platform ios` on a Mac to validate the Xcode project
|
||||
- [ ] Prepare the Mac build worker (macbook13-pro at 100.68.120.26) as GitHub self-hosted runner
|
||||
|
||||
---
|
||||
|
||||
## After Enrollment Approval — App Store Connect Setup
|
||||
|
||||
1. Create a new App in App Store Connect:
|
||||
- Platform: iOS
|
||||
- Name: `OpenCode`
|
||||
- Primary Language: English (U.S.)
|
||||
- Bundle ID: `ai.opencode.mobile` — register this explicit App ID first at https://developer.apple.com/account/resources/identifiers/
|
||||
- SKU: `ai.opencode.mobile` (can match bundle ID)
|
||||
|
||||
2. Configure App ID capabilities needed:
|
||||
- Push Notifications (for `expo-notifications`)
|
||||
- Associated Domains (if deep linking via `opencode://` is used externally — not strictly needed for current app)
|
||||
|
||||
3. Create App Store Connect API Key for CI:
|
||||
- Go to https://appstoreconnect.apple.com/access/api
|
||||
- Create key with **App Manager** role
|
||||
- Download the `.p8` file (can only be downloaded once!)
|
||||
- Note: Key ID and Issuer ID
|
||||
- Base64-encode the .p8 and store in GitHub secret `APPLE_APP_STORE_CONNECT_API_KEY`
|
||||
|
||||
4. Create an internal TestFlight group and add yourself as tester
|
||||
|
||||
---
|
||||
|
||||
## Cost Summary
|
||||
|
||||
| Item | Cost | Frequency |
|
||||
|---|---|---|
|
||||
| Apple Developer Program | $99 USD | Per year (auto-renews) |
|
||||
| EAS Build (free tier) | $0 | Up to 30 builds/month for iOS |
|
||||
| EAS Build (production tier) | $19/month | Unlimited builds, priority queue |
|
||||
| macOS GitHub runner | ~$0.08/min × ~25 min/build ≈ $2/build | Per build |
|
||||
|
||||
**Recommendation**: Start with EAS Build free tier for first few releases. Upgrade to production tier ($19/month) if build queue times become a problem. See task 2 analysis in the final report.
|
||||
|
||||
---
|
||||
|
||||
## Timeline Estimate
|
||||
|
||||
| Milestone | Estimated Time from Starting Enrollment |
|
||||
|---|---|
|
||||
| Enrollment form submitted | Day 0 |
|
||||
| Apple verification call | Day 2–5 |
|
||||
| Enrollment approved + payment | Day 3–7 |
|
||||
| Banking/tax info set up | Day 7–8 |
|
||||
| App ID + provisioning profile created | Day 8 |
|
||||
| First TestFlight build submitted via CI | Day 9–10 |
|
||||
| TestFlight internal testers can install | Day 9–10 (no review for internal) |
|
||||
| App Store production submission | Day 10–12 |
|
||||
| Apple review complete + production live | Day 12–14 (review typically 24–48 hours) |
|
||||
110
distribution/izzyondroid-submission/INCLUSION-REQUEST.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# IzzyOnDroid Inclusion Request
|
||||
|
||||
**File this as a new issue at: https://codeberg.org/IzzyOnDroid/repodata/issues**
|
||||
|
||||
Use the text below (starting from "---") as the issue body. Replace all
|
||||
`<PLACEHOLDER>` values before filing.
|
||||
|
||||
---
|
||||
|
||||
## App submission: OpenCode Mobile
|
||||
|
||||
**App name:** OpenCode Mobile
|
||||
**Package / App ID:** `ai.opencode.mobile`
|
||||
**License:** MIT
|
||||
**Source code:** https://github.com/dzianisv/opencode-mobile
|
||||
**GitHub releases:** https://github.com/dzianisv/opencode-mobile/releases
|
||||
|
||||
---
|
||||
|
||||
### Release URL pattern
|
||||
|
||||
APK attached to each GitHub release tag following the pattern:
|
||||
|
||||
```
|
||||
https://github.com/dzianisv/opencode-mobile/releases/download/<TAG>/app-release.apk
|
||||
```
|
||||
|
||||
Example (first production release):
|
||||
```
|
||||
https://github.com/dzianisv/opencode-mobile/releases/download/v0.2.4/app-release.apk
|
||||
```
|
||||
|
||||
Note: IzzyOnDroid should use the GitHub releases tag pattern for auto-update
|
||||
polling. The app uses semantic versioning (`vX.Y.Z` tags).
|
||||
|
||||
---
|
||||
|
||||
### Signing key SHA-256 fingerprint
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
This is the production-release.jks key used for all distribution channels
|
||||
(Play Store, F-Droid, and IzzyOnDroid use the same signing key — users can
|
||||
update in-place across stores).
|
||||
|
||||
---
|
||||
|
||||
### Description
|
||||
|
||||
OpenCode Mobile is a free, open-source (MIT) client for the opencode AI coding
|
||||
agent (sst/opencode). It lets developers connect to their self-hosted opencode
|
||||
server and drive AI-powered coding sessions from their Android phone.
|
||||
|
||||
Key features include streaming chat with the AI agent, a file diff viewer for
|
||||
reviewing proposed code changes before accepting them, multi-session management,
|
||||
tool call approval gates, and biometric unlock. All AI traffic flows directly
|
||||
from the app to the user's own server — no middleman, no mandatory accounts, no
|
||||
vendor lock-in. Crash reporting via Sentry is opt-in with default OFF.
|
||||
|
||||
The app is aimed at developers who run opencode on a workstation or self-hosted
|
||||
server (on-prem or any cloud VPS) and want a mobile companion for on-the-go
|
||||
session management. An optional hosted "opencode Cloud" backend is planned as
|
||||
a future paid service, but the client is and will remain free and open source.
|
||||
|
||||
---
|
||||
|
||||
### Anti-features acknowledgment
|
||||
|
||||
**NonFreeNet** applies: the app connects to a user-self-hosted opencode server
|
||||
which may in turn connect to proprietary AI APIs (OpenAI, Anthropic, Google
|
||||
Gemini). The app itself contains no proprietary network code and does not
|
||||
require any specific provider.
|
||||
|
||||
No other anti-features apply:
|
||||
- No ads (no ad SDK present)
|
||||
- No tracking (Sentry opt-in, default OFF — user must explicitly enable)
|
||||
- No non-free dependencies beyond FCM receiver classes compiled in by
|
||||
`expo-notifications` (local-only usage; `scheduleNotificationAsync` only;
|
||||
no `getExpoPushTokenAsync` / `getDevicePushTokenAsync` calls)
|
||||
- No subscription / license checks in the client
|
||||
|
||||
---
|
||||
|
||||
### FOSS confirmation
|
||||
|
||||
- Source code is fully public: https://github.com/dzianisv/opencode-mobile
|
||||
- License: MIT (https://github.com/dzianisv/opencode-mobile/blob/main/LICENSE
|
||||
or inferred from package.json `"license": "MIT"`)
|
||||
- No proprietary SDKs are required for core functionality
|
||||
- The APK on GitHub releases is signed with the key fingerprint above
|
||||
|
||||
---
|
||||
|
||||
### F-Droid mainline track note
|
||||
|
||||
A parallel F-Droid mainline submission (MR against fdroiddata) will be filed
|
||||
after the first Play Store release is live. Per IzzyOnDroid policy, IzzyOnDroid
|
||||
will auto-delist this app once the mainline F-Droid repository accepts it.
|
||||
We will notify the IzzyOnDroid team via this issue when that happens.
|
||||
|
||||
---
|
||||
|
||||
### Contact
|
||||
|
||||
Developer: VIBE TECHNOLOGIES, LLC
|
||||
Email: support@vibebrowser.app
|
||||
Website: https://opencode.vibebrowser.app
|
||||
Privacy policy: https://opencode.vibebrowser.app/privacy
|
||||
112
distribution/izzyondroid-submission/SUBMISSION-CHECKLIST.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# IzzyOnDroid Submission Checklist
|
||||
|
||||
Step-by-step guide to file the inclusion request for `ai.opencode.mobile`
|
||||
in the IzzyOnDroid F-Droid repository.
|
||||
|
||||
IzzyOnDroid is the fastest OSS distribution channel — typical inclusion is
|
||||
1–3 days after filing. It serves pre-built APKs directly from GitHub releases.
|
||||
|
||||
**Pre-condition: a signed APK must be attached to a GitHub release tag before filing.**
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [ ] Signed release APK (not AAB) exists and is attached to a GitHub tag
|
||||
(e.g. `https://github.com/dzianisv/opencode-mobile/releases/tag/v0.2.4`)
|
||||
- [ ] APK is signed with `keystores/production-release.jks`
|
||||
- [ ] SHA-256 fingerprint confirmed: see `distribution/SIGNING-KEY-FINGERPRINTS.md`
|
||||
- [ ] Sentry opt-in gate is in production (avoids `Tracking` anti-feature escalation)
|
||||
- [ ] Privacy policy is live at `https://opencode.vibebrowser.app/privacy`
|
||||
- [ ] `app.json` `version` and `android.versionCode` are set correctly in the tagged commit
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — Attach APK to GitHub release
|
||||
|
||||
The CI workflow currently builds an AAB (for Play Store). For IzzyOnDroid and
|
||||
F-Droid you need a **universal APK**.
|
||||
|
||||
Option A — Convert AAB to universal APK with bundletool:
|
||||
```bash
|
||||
bundletool build-apks \
|
||||
--bundle=android/app/build/outputs/bundle/release/app-release.aab \
|
||||
--output=apks.apks \
|
||||
--mode=universal \
|
||||
--ks=keystores/production-release.jks \
|
||||
--ks-pass=pass:<STOREPASS> \
|
||||
--ks-key-alias=<KEY_ALIAS> \
|
||||
--key-pass=pass:<KEY_PASS>
|
||||
|
||||
unzip apks.apks universal.apk -d apk-out/
|
||||
# Resulting APK: apk-out/universal.apk → rename to app-release.apk
|
||||
```
|
||||
|
||||
Option B — Add `assembleRelease` to CI alongside `bundleRelease`, then
|
||||
attach the resulting `app-release.apk` to the GitHub release artifact.
|
||||
|
||||
Whichever option, attach the `.apk` file to the GitHub release created by the
|
||||
release tag.
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — Verify the APK
|
||||
|
||||
```bash
|
||||
# Confirm package id and version
|
||||
aapt dump badging apk-out/universal.apk | grep -E "package:|versionCode|versionName"
|
||||
# Expected:
|
||||
# package: name='ai.opencode.mobile' versionCode='<N>' versionName='<X.Y.Z>'
|
||||
|
||||
# Confirm signing fingerprint matches distribution/SIGNING-KEY-FINGERPRINTS.md
|
||||
apksigner verify --print-certs apk-out/universal.apk | grep SHA-256
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — Create a Codeberg account (if needed)
|
||||
|
||||
IzzyOnDroid issues are hosted on Codeberg (not GitHub).
|
||||
URL: https://codeberg.org
|
||||
|
||||
Register or log in at https://codeberg.org/user/sign_up
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — File the inclusion issue
|
||||
|
||||
1. Go to https://codeberg.org/IzzyOnDroid/repodata/issues
|
||||
2. Click "New Issue"
|
||||
3. Title: `Include ai.opencode.mobile (OpenCode Mobile)`
|
||||
4. Body: paste the content from `distribution/izzyondroid-submission/INCLUSION-REQUEST.md`
|
||||
(with all `<PLACEHOLDER>` values replaced)
|
||||
5. Submit
|
||||
|
||||
---
|
||||
|
||||
## Step 5 — Monitor and respond
|
||||
|
||||
- IzzyOnDroid maintainers typically respond within 1–3 days.
|
||||
- Common requests:
|
||||
- Confirm APK URL pattern resolves correctly
|
||||
- Confirm signing key fingerprint via `apksigner` output
|
||||
- Clarification on anti-features
|
||||
- Once accepted, the app appears in the next IzzyOnDroid index build (usually within 24h).
|
||||
|
||||
---
|
||||
|
||||
## Step 6 — After acceptance
|
||||
|
||||
- Add the IzzyOnDroid badge to `README.md`
|
||||
- Update `distribution/strategy.md` status row for IzzyOnDroid to "live"
|
||||
- Update `docs/fdroid.md` with inclusion date
|
||||
- When mainline F-Droid MR is later accepted, comment on this issue:
|
||||
"Mainline F-Droid has accepted ai.opencode.mobile — please auto-delist per policy."
|
||||
|
||||
---
|
||||
|
||||
## Reference
|
||||
|
||||
- IzzyOnDroid inclusion policy: https://apt.izzysoft.de/fdroid/index/info
|
||||
- Codeberg issues: https://codeberg.org/IzzyOnDroid/repodata/issues
|
||||
- IzzyOnDroid repo (for badge URLs): https://apt.izzysoft.de/fdroid/index/apk/ai.opencode.mobile
|
||||
BIN
distribution/play-graphics/feature-graphic.png
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
distribution/play-graphics/icon-512.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
distribution/play-graphics/phone-01.png
Normal file
|
After Width: | Height: | Size: 134 KiB |
BIN
distribution/play-graphics/phone-02.png
Normal file
|
After Width: | Height: | Size: 140 KiB |
BIN
distribution/play-graphics/phone-03.png
Normal file
|
After Width: | Height: | Size: 151 KiB |
260
distribution/play-listing.md
Normal file
@@ -0,0 +1,260 @@
|
||||
# Google Play Store Listing — OpenCode
|
||||
|
||||
Copy-paste reference for completing the Play Console store listing for `ai.opencode.mobile`.
|
||||
Once identity verification is approved and the app is created, paste these values directly.
|
||||
|
||||
---
|
||||
|
||||
## Main store listing
|
||||
|
||||
### App name (max 30 chars)
|
||||
|
||||
```
|
||||
OpenCode
|
||||
```
|
||||
(8 chars — well under limit)
|
||||
|
||||
### Short description (max 80 chars)
|
||||
|
||||
```
|
||||
Drive your self-hosted AI coding agent from your phone.
|
||||
```
|
||||
(55 chars)
|
||||
|
||||
### Full description (max 4000 chars)
|
||||
|
||||
```
|
||||
OpenCode is an open-source mobile client for the opencode AI coding agent (sst/opencode). Connect to your self-hosted opencode server and drive AI-powered coding sessions from your phone.
|
||||
|
||||
KEY FEATURES
|
||||
|
||||
• Multiple connection types — local network, secure tunnels (Cloudflare, ngrok), or cloud-hosted opencode instances
|
||||
• Biometric unlock — Face ID / Touch ID / fingerprint to keep your sessions private
|
||||
• Real-time streaming chat — watch your AI agent think and respond live
|
||||
• File diff viewer — see exactly what code changes the agent is making before you accept
|
||||
• Multi-session management — start, resume, and switch between coding sessions
|
||||
• Tool call approval — review and approve actions before the agent runs them on your code
|
||||
|
||||
WHO IT'S FOR
|
||||
|
||||
• Developers who run opencode (sst/opencode) on their workstation or a server
|
||||
• Engineers who want to check in on long-running coding sessions away from their desk
|
||||
• Teams who self-host AI dev tools and want a polished mobile companion
|
||||
|
||||
WHAT IT IS NOT
|
||||
|
||||
• Not an AI model — you bring your own opencode server (which connects to Claude, GPT, Gemini, or local models)
|
||||
• Not a code editor — pair with your existing IDE/terminal workflow
|
||||
• Not a Google Play exclusive — also available on F-Droid (open source build)
|
||||
|
||||
OPEN SOURCE
|
||||
|
||||
OpenCode Mobile is MIT licensed. Source code, issue tracker, and community discussion:
|
||||
https://github.com/dzianisv/opencode-mobile
|
||||
|
||||
PRIVACY
|
||||
|
||||
OpenCode Mobile does not collect your code or prompts. All AI traffic goes directly from the app to YOUR opencode server. We use Sentry for crash reporting only (no PII, no message content). See our privacy policy for details.
|
||||
|
||||
SUPPORT
|
||||
|
||||
Email: support@vibebrowser.app
|
||||
Issues: https://github.com/dzianisv/opencode-mobile/issues
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Graphic assets — REQUIRED before publishing
|
||||
|
||||
| Asset | Spec | Status | Notes |
|
||||
|---|---|---|---|
|
||||
| App icon | 512×512 PNG, 32-bit, ≤1 MB | ❌ placeholder | `assets/icon.json` is `{"placeholder":true}` — need real PNG |
|
||||
| Adaptive icon (foreground) | 432×432 PNG, transparent bg | ❌ placeholder | `assets/adaptive-icon.json` placeholder |
|
||||
| Feature graphic | 1024×500 PNG/JPG | ❌ missing | For Play Store top banner — required for publishing |
|
||||
| Phone screenshots | 2–8 images, 16:9 or 9:16, 1080×1920 or similar | ❌ missing | Required min 2 |
|
||||
| 7-inch tablet screenshots | optional | ❌ missing | Recommended |
|
||||
| 10-inch tablet screenshots | optional | ❌ missing | Recommended |
|
||||
| Promo video | YouTube URL, optional | ⏸ skip for first release | |
|
||||
|
||||
**Action**: design + generate assets. Suggested tools:
|
||||
- Icon: Figma → 1024×1024 → export to `assets/icon.png` + run `npx expo prebuild` to fan out per-density.
|
||||
- Screenshots: run app on emulator, capture via Android Studio screenshot, or use Fastlane's snapshot tooling.
|
||||
|
||||
---
|
||||
|
||||
## Categorization
|
||||
|
||||
| Field | Value | Notes |
|
||||
|---|---|---|
|
||||
| App or game | App | |
|
||||
| Category | Tools | Best fit. Alternatives: Productivity, Communication. |
|
||||
| Tags | productivity, developer, ai, coding | Free tags. |
|
||||
| Email | support@vibebrowser.app | Already verified during signup. |
|
||||
| Phone | +1 360-504-8967 | Optional public; matches developer profile. |
|
||||
| Website | https://www.vibebrowser.app/ | Already verified. |
|
||||
|
||||
---
|
||||
|
||||
## Privacy policy URL
|
||||
|
||||
**Required.** Must be a public URL.
|
||||
|
||||
Suggested path: `https://opencode.vibebrowser.app/privacy`
|
||||
|
||||
Privacy policy must cover (per Google requirements):
|
||||
- What data is collected (Sentry crash diagnostics: device model, OS version, stack trace; nothing user-content)
|
||||
- How data is used (debugging crashes only)
|
||||
- Third-party SDKs (Sentry — link to https://sentry.io/privacy/)
|
||||
- Data retention (Sentry default 90 days)
|
||||
- User rights (delete account, contact us)
|
||||
- Contact: support@vibebrowser.app
|
||||
|
||||
**Action**: write a privacy policy at the URL above. Template draft below.
|
||||
|
||||
```
|
||||
OpenCode Mobile Privacy Policy
|
||||
Effective: 2026-05-24
|
||||
Operator: VIBE TECHNOLOGIES, LLC, 519 S Henderson St, Seattle WA 98108-4522 USA
|
||||
|
||||
We do not collect your code, prompts, AI responses, server URLs, or chat history.
|
||||
|
||||
We collect (via Sentry SDK for crash reporting):
|
||||
- Device model, OS version, app version
|
||||
- Stack traces of crashes and unhandled errors
|
||||
- App breadcrumbs (function names, screen names — no message bodies)
|
||||
|
||||
Data is sent to Sentry (sentry.io) and retained per Sentry defaults (~90 days).
|
||||
|
||||
Third-party services:
|
||||
- Sentry — crash reporting. https://sentry.io/privacy/
|
||||
|
||||
Data sharing: none beyond Sentry.
|
||||
|
||||
User rights:
|
||||
- Email support@vibebrowser.app to request deletion of crash records associated with your device.
|
||||
|
||||
Contact: support@vibebrowser.app
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data safety form
|
||||
|
||||
Google requires this before publishing. Answers below for OpenCode Mobile current state.
|
||||
|
||||
| Question | Answer |
|
||||
|---|---|
|
||||
| Does your app collect or share any of the required user data types? | Yes |
|
||||
| Is all of the user data collected by your app encrypted in transit? | Yes (HTTPS to Sentry) |
|
||||
| Do you provide a way for users to request that their data is deleted? | Yes — via support@vibebrowser.app |
|
||||
|
||||
### Data types collected
|
||||
|
||||
| Data type | Collected? | Shared? | Optional? | Purpose | Encrypted in transit? |
|
||||
|---|---|---|---|---|---|
|
||||
| App crash logs (Diagnostics) | Yes | Yes (Sentry) | **Yes (opt-in, default OFF)** | App functionality, diagnostics | Yes |
|
||||
| App performance / interactions | No | – | – | – | – |
|
||||
| Device or other IDs | No | – | – | – | – |
|
||||
| Personal info (name, email, etc.) | No | – | – | – | – |
|
||||
| Financial info | No | – | – | – | – |
|
||||
| Health / fitness | No | – | – | – | – |
|
||||
| Messages | No | – | – | – | – |
|
||||
| Photos / videos | No | – | – | – | – |
|
||||
| Audio | No | – | – | – | – |
|
||||
| Files and docs | No | – | – | – | – |
|
||||
| Calendar | No | – | – | – | – |
|
||||
| Contacts | No | – | – | – | – |
|
||||
| App activity (searches, viewed content) | No | – | – | – | – |
|
||||
| Web browsing | No | – | – | – | – |
|
||||
| App info and performance (other than crash logs) | No | – | – | – | – |
|
||||
|
||||
---
|
||||
|
||||
## Content rating
|
||||
|
||||
Run the IARC questionnaire on Play Console. Expected outcome based on app content:
|
||||
|
||||
| Region | Expected rating |
|
||||
|---|---|
|
||||
| ESRB (US) | Everyone |
|
||||
| PEGI (EU) | 3 |
|
||||
| USK (Germany) | 0 |
|
||||
| Australia | G |
|
||||
|
||||
Questionnaire answers (all "No" since no violence / sexual / drugs / gambling / etc. content; app is a dev tool):
|
||||
- Does it contain violence? No
|
||||
- Does it contain sexual content? No
|
||||
- Does it contain crude humor? No
|
||||
- Does it use drugs/alcohol/tobacco? No
|
||||
- Does it contain gambling? No
|
||||
- Does it share user location? No
|
||||
- Does it share user-generated content? No (private user → user-self only)
|
||||
- Does it allow users to interact / chat? Yes (with their OWN backend, not other users)
|
||||
|
||||
If "interact with other users" is asked: answer NO — the chat is between the user and their own AI agent, not user-to-user.
|
||||
|
||||
---
|
||||
|
||||
## Target audience and content
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Target age group | 18+ (developer tool) |
|
||||
| Appeals to children? | No |
|
||||
| Ads? | No |
|
||||
| In-app purchases? | (TBD — see monetization decision) |
|
||||
|
||||
---
|
||||
|
||||
## App access
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| All functionality available without restrictions? | No — requires user to provide their own opencode server URL |
|
||||
| Provide test credentials? | Yes — provide Google reviewer with a temporary opencode server URL or instructions to spin one up |
|
||||
|
||||
Reviewer instructions (paste in App Access form):
|
||||
|
||||
```
|
||||
OpenCode Mobile requires the user to bring their own opencode server (https://opencode.ai). To review the app:
|
||||
|
||||
1. Install opencode on any machine: `npm install -g opencode-ai`
|
||||
2. Run `opencode serve` — prints a local URL like http://localhost:4096
|
||||
3. In the app, tap "Connect" → enter the URL → connect.
|
||||
4. Start a session, type a prompt, observe streaming response.
|
||||
|
||||
If reviewers cannot self-host, contact support@vibebrowser.app and we will provide a temporary hosted opencode endpoint for review.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Release notes / "What's new" per release
|
||||
|
||||
Already wired in CI: `distribution/whatsnew/whatsnew-en-US`.
|
||||
|
||||
Bump this file before tagging a release. Keep it under 500 chars. Per-language variants supported (`whatsnew-fr-FR`, `whatsnew-de-DE`, etc.).
|
||||
|
||||
---
|
||||
|
||||
## First release strategy
|
||||
|
||||
1. **Internal testing** track first (up to 100 testers, no review) — what CI is wired for.
|
||||
2. **Closed testing** — 14+ days, 12+ testers required for new org accounts before promoting to production (Google's 2023 policy).
|
||||
3. **Open testing** — optional intermediate step.
|
||||
4. **Production** — only after Closed testing requirements met.
|
||||
|
||||
CI currently publishes to `internal` track ✅ correct for first release.
|
||||
|
||||
---
|
||||
|
||||
## Pending before first publish
|
||||
|
||||
- [ ] Identity verification (governor ID upload, Google review days)
|
||||
- [ ] App icon (real PNG, not placeholder)
|
||||
- [ ] Adaptive icon (real PNG)
|
||||
- [ ] Feature graphic 1024×500
|
||||
- [ ] At least 2 phone screenshots
|
||||
- [ ] Privacy policy live at https://opencode.vibebrowser.app/privacy
|
||||
- [ ] Decide pricing model (see monetization research)
|
||||
- [ ] Run IARC content rating questionnaire (after app created)
|
||||
- [ ] Complete Data safety form (after app created)
|
||||
313
distribution/privacy-policy.html
Normal file
@@ -0,0 +1,313 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>OpenCode Mobile — Privacy Policy</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.7;
|
||||
color: #1a1a2e;
|
||||
background: #ffffff;
|
||||
padding: 24px 16px 64px;
|
||||
max-width: 760px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
header {
|
||||
border-bottom: 2px solid #3b82f6;
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
header h1 {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
header .meta {
|
||||
font-size: 14px;
|
||||
color: #64748b;
|
||||
}
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #0f172a;
|
||||
margin-top: 36px;
|
||||
margin-bottom: 12px;
|
||||
border-left: 4px solid #3b82f6;
|
||||
padding-left: 12px;
|
||||
}
|
||||
p { margin-bottom: 14px; }
|
||||
ul {
|
||||
margin: 10px 0 14px 24px;
|
||||
}
|
||||
ul li { margin-bottom: 6px; }
|
||||
a { color: #3b82f6; text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
.highlight-box {
|
||||
background: #eff6ff;
|
||||
border: 1px solid #bfdbfe;
|
||||
border-radius: 8px;
|
||||
padding: 16px 20px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.highlight-box strong { color: #1e40af; }
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 14px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
th {
|
||||
background: #f1f5f9;
|
||||
text-align: left;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid #e2e8f0;
|
||||
font-weight: 600;
|
||||
}
|
||||
td {
|
||||
padding: 10px 12px;
|
||||
border: 1px solid #e2e8f0;
|
||||
vertical-align: top;
|
||||
}
|
||||
tr:nth-child(even) td { background: #f8fafc; }
|
||||
footer {
|
||||
margin-top: 48px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #e2e8f0;
|
||||
font-size: 13px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<h1>OpenCode Mobile — Privacy Policy</h1>
|
||||
<p class="meta">
|
||||
Effective date: 2026-05-24 |
|
||||
Operator: VIBE TECHNOLOGIES, LLC |
|
||||
App: OpenCode Mobile (<code>ai.opencode.mobile</code>)
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div class="highlight-box">
|
||||
<strong>Summary:</strong> OpenCode Mobile does not collect your code, prompts, AI responses,
|
||||
server URLs, or any chat content. All AI traffic goes directly from the app to your own
|
||||
opencode server. We use Sentry only for anonymous crash diagnostics, and only with your
|
||||
consent.
|
||||
</div>
|
||||
|
||||
<h2>1. Who We Are</h2>
|
||||
<p>
|
||||
OpenCode Mobile is developed and distributed by <strong>VIBE TECHNOLOGIES, LLC</strong>,
|
||||
a Washington State limited liability company.<br>
|
||||
Address: 519 S Henderson St, Seattle, WA 98108-4522, USA<br>
|
||||
Contact: <a href="mailto:support@vibebrowser.app">support@vibebrowser.app</a>
|
||||
</p>
|
||||
<p>
|
||||
The app is open-source (MIT license). Source code:
|
||||
<a href="https://github.com/dzianisv/opencode-mobile">github.com/dzianisv/opencode-mobile</a>.
|
||||
</p>
|
||||
|
||||
<h2>2. Data We Do NOT Collect</h2>
|
||||
<p>
|
||||
We want to be explicit about what we never collect, transmit to our servers, or share with
|
||||
third parties:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Your code, files, or repository content</li>
|
||||
<li>Your prompts, chat messages, or AI responses</li>
|
||||
<li>Your opencode server URL, IP address, or hostname</li>
|
||||
<li>Authentication tokens, API keys, or credentials you enter</li>
|
||||
<li>Account information, email addresses, or names</li>
|
||||
<li>Location data</li>
|
||||
<li>Photos, microphone recordings, or camera data (unless you attach them to a message,
|
||||
in which case they go only to your own server)</li>
|
||||
<li>Contacts, calendar, or any other personal data</li>
|
||||
</ul>
|
||||
<p>
|
||||
All communication between the app and your AI coding agent travels directly between your
|
||||
device and your self-hosted opencode server. VIBE TECHNOLOGIES, LLC never sees this traffic.
|
||||
</p>
|
||||
|
||||
<h2>3. Data We Do Collect (Crash Diagnostics)</h2>
|
||||
<p>
|
||||
With your explicit consent (shown at first launch), we collect anonymous crash diagnostic
|
||||
data via <strong>Sentry</strong> to help us identify and fix bugs.
|
||||
</p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Data type</th>
|
||||
<th>What is captured</th>
|
||||
<th>What is NOT captured</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Device info</td>
|
||||
<td>Device model (e.g. "Pixel 7"), OS version, screen resolution, app version</td>
|
||||
<td>Device serial number, IMEI, advertising ID</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Crash / error reports</td>
|
||||
<td>Stack traces, exception types and messages, source file names and line numbers</td>
|
||||
<td>Variable values at time of crash, no user data in scope</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Breadcrumbs</td>
|
||||
<td>Screen names and function call sequence leading to the crash (e.g., "navigated to session screen")</td>
|
||||
<td>Message bodies, server URLs, prompt text — all stripped before upload by our URL-scrubbing filter</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>App version and build</td>
|
||||
<td>Version string and build number</td>
|
||||
<td>—</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
URL scrubbing: before any event is sent to Sentry, our code strips all server URLs,
|
||||
authentication tokens, and query parameters. Stack traces are checked for embedded URLs.
|
||||
No server hostname or port number ever leaves your device via Sentry.
|
||||
</p>
|
||||
|
||||
<h2>4. Consent and Control</h2>
|
||||
<p>
|
||||
Crash reporting is <strong>opt-in and off by default</strong>. The first time you launch
|
||||
the app you will see a consent prompt. You can change this at any time:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Open the app → <strong>Settings</strong> → <strong>Privacy</strong> →
|
||||
<strong>Crash reporting</strong> toggle.</li>
|
||||
<li>When the toggle is off, Sentry is never initialised and no data leaves your device.</li>
|
||||
</ul>
|
||||
|
||||
<h2>5. Third-Party Services</h2>
|
||||
<p>
|
||||
We use one third-party service for diagnostics:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Sentry</strong> — crash and error monitoring.<br>
|
||||
Privacy policy: <a href="https://sentry.io/privacy/" target="_blank" rel="noopener">sentry.io/privacy</a><br>
|
||||
Data is sent to Sentry's US-based servers and retained for approximately 90 days
|
||||
per Sentry's default data-retention policy.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
We use no advertising networks, analytics platforms, social SDKs, or any other
|
||||
third-party data collection services. The app contains no ads and no ad SDKs.
|
||||
</p>
|
||||
|
||||
<h2>6. Data Retention</h2>
|
||||
<p>
|
||||
Crash reports sent to Sentry are retained for approximately 90 days, after which they are
|
||||
automatically deleted per Sentry's retention defaults.
|
||||
</p>
|
||||
<p>
|
||||
We do not operate our own servers that store your data; there is no VIBE TECHNOLOGIES
|
||||
back end involved in normal app usage.
|
||||
</p>
|
||||
|
||||
<h2>7. Your Rights</h2>
|
||||
<p>
|
||||
You have the right to:
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>Opt out</strong> — disable crash reporting at any time in Settings → Privacy.</li>
|
||||
<li><strong>Request deletion</strong> — email <a href="mailto:support@vibebrowser.app">support@vibebrowser.app</a>
|
||||
with subject "Data deletion request" and we will request deletion of any crash events
|
||||
associated with your device from Sentry. Include your device model and approximate date
|
||||
range to help us identify your records.</li>
|
||||
<li><strong>Access</strong> — request a summary of what diagnostic data (if any) we hold
|
||||
about your device by emailing the same address.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Residents of the EU/EEA/UK may exercise rights under GDPR/UK GDPR. California residents
|
||||
may exercise rights under the CCPA. To do so, contact us at the email above.
|
||||
</p>
|
||||
|
||||
<h2>8. Children</h2>
|
||||
<p>
|
||||
OpenCode Mobile is a developer tool intended for users aged 18 and over. We do not
|
||||
knowingly collect any data from children under 13 (or under 16 in the EU). If you believe
|
||||
a child has submitted data, please contact us and we will delete it promptly.
|
||||
</p>
|
||||
|
||||
<h2>9. Security</h2>
|
||||
<p>
|
||||
All diagnostic data is transmitted over HTTPS (TLS 1.2+) to Sentry. We do not transmit
|
||||
any data over unencrypted connections. Your opencode server traffic uses whatever transport
|
||||
security your server provides — we recommend HTTPS for all self-hosted deployments.
|
||||
</p>
|
||||
|
||||
<h2>10. Changes to This Policy</h2>
|
||||
<p>
|
||||
If we make material changes to this policy, we will update the effective date at the top
|
||||
of this page and, where feasible, notify users via an in-app notice. The latest version
|
||||
is always available at:
|
||||
<a href="https://opencode.vibebrowser.app/privacy">
|
||||
vibebrowser.app/opencode-mobile/privacy
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h2>11. Contact</h2>
|
||||
<p>
|
||||
VIBE TECHNOLOGIES, LLC<br>
|
||||
519 S Henderson St<br>
|
||||
Seattle, WA 98108-4522<br>
|
||||
USA<br>
|
||||
Email: <a href="mailto:support@vibebrowser.app">support@vibebrowser.app</a>
|
||||
</p>
|
||||
|
||||
<hr style="margin:40px 0; border:none; border-top:1px solid #e2e8f0;">
|
||||
|
||||
<h2>Apple-Specific Addendum (iOS / App Store)</h2>
|
||||
<p>This addendum addresses Apple's specific privacy disclosure requirements for iOS apps distributed through the Apple App Store.</p>
|
||||
|
||||
<h3>App Tracking Transparency (ATT)</h3>
|
||||
<p>OpenCode Mobile does <strong>not</strong> use Apple's App Tracking Transparency (<code>AppTrackingTransparency</code>) framework. The app does not:</p>
|
||||
<ul>
|
||||
<li>Access the IDFA (Identifier for Advertisers)</li>
|
||||
<li>Use any cross-app or cross-website tracking</li>
|
||||
<li>Participate in any advertising network</li>
|
||||
<li>Profile users for advertising or marketing purposes</li>
|
||||
</ul>
|
||||
<p>No ATT permission prompt is ever shown to users because there is nothing to track.</p>
|
||||
|
||||
<h3>Apple Privacy Nutrition Label Data Categories</h3>
|
||||
<p>The following maps our data practices to Apple's official App Privacy categories (as required in App Store Connect):</p>
|
||||
<table style="width:100%;border-collapse:collapse;font-size:14px;margin:16px 0;">
|
||||
<thead>
|
||||
<tr style="background:#f1f5f9;">
|
||||
<th style="border:1px solid #e2e8f0;padding:8px;text-align:left;">Apple Category</th>
|
||||
<th style="border:1px solid #e2e8f0;padding:8px;text-align:left;">Collected?</th>
|
||||
<th style="border:1px solid #e2e8f0;padding:8px;text-align:left;">Linked to identity?</th>
|
||||
<th style="border:1px solid #e2e8f0;padding:8px;text-align:left;">Used for tracking?</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td style="border:1px solid #e2e8f0;padding:8px;">Contact Info</td><td style="border:1px solid #e2e8f0;padding:8px;">No</td><td style="border:1px solid #e2e8f0;padding:8px;">N/A</td><td style="border:1px solid #e2e8f0;padding:8px;">No</td></tr>
|
||||
<tr><td style="border:1px solid #e2e8f0;padding:8px;">Location</td><td style="border:1px solid #e2e8f0;padding:8px;">No</td><td style="border:1px solid #e2e8f0;padding:8px;">N/A</td><td style="border:1px solid #e2e8f0;padding:8px;">No</td></tr>
|
||||
<tr><td style="border:1px solid #e2e8f0;padding:8px;">Identifiers (Device ID)</td><td style="border:1px solid #e2e8f0;padding:8px;">Yes (Sentry anonymous ID, with consent)</td><td style="border:1px solid #e2e8f0;padding:8px;">No</td><td style="border:1px solid #e2e8f0;padding:8px;">No</td></tr>
|
||||
<tr><td style="border:1px solid #e2e8f0;padding:8px;">Diagnostics — Crash Data</td><td style="border:1px solid #e2e8f0;padding:8px;">Yes (Sentry, with consent)</td><td style="border:1px solid #e2e8f0;padding:8px;">No</td><td style="border:1px solid #e2e8f0;padding:8px;">No</td></tr>
|
||||
<tr><td style="border:1px solid #e2e8f0;padding:8px;">Diagnostics — Performance Data</td><td style="border:1px solid #e2e8f0;padding:8px;">Yes (Sentry, with consent)</td><td style="border:1px solid #e2e8f0;padding:8px;">No</td><td style="border:1px solid #e2e8f0;padding:8px;">No</td></tr>
|
||||
<tr><td style="border:1px solid #e2e8f0;padding:8px;">All other categories</td><td style="border:1px solid #e2e8f0;padding:8px;">No</td><td style="border:1px solid #e2e8f0;padding:8px;">N/A</td><td style="border:1px solid #e2e8f0;padding:8px;">No</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><strong>App Store Connect summary:</strong> Data Linked to You: <em>None</em>. Data Not Linked to You: <em>Crash Data, Performance Data</em> (when user consents). Tracking: <em>No</em>.</p>
|
||||
|
||||
<footer>
|
||||
© 2026 VIBE TECHNOLOGIES, LLC. OpenCode Mobile is MIT-licensed open-source software.
|
||||
Privacy policy effective 2026-05-24.
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
164
distribution/privacy-policy.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# OpenCode Mobile — Privacy Policy
|
||||
|
||||
**Effective date:** 2026-05-24
|
||||
**Operator:** VIBE TECHNOLOGIES, LLC
|
||||
**App:** OpenCode Mobile (`ai.opencode.mobile`)
|
||||
|
||||
> **Summary:** OpenCode Mobile does not collect your code, prompts, AI responses, server URLs, or any chat content. All AI traffic goes directly from the app to your own opencode server. We use Sentry only for anonymous crash diagnostics, and only with your consent.
|
||||
|
||||
---
|
||||
|
||||
## 1. Who We Are
|
||||
|
||||
OpenCode Mobile is developed and distributed by **VIBE TECHNOLOGIES, LLC**, a Washington State limited liability company.
|
||||
|
||||
- Address: 519 S Henderson St, Seattle, WA 98108-4522, USA
|
||||
- Contact: support@vibebrowser.app
|
||||
- Source code: https://github.com/dzianisv/opencode-mobile (MIT license)
|
||||
|
||||
---
|
||||
|
||||
## 2. Data We Do NOT Collect
|
||||
|
||||
We never collect, transmit to our servers, or share with third parties:
|
||||
|
||||
- Your code, files, or repository content
|
||||
- Your prompts, chat messages, or AI responses
|
||||
- Your opencode server URL, IP address, or hostname
|
||||
- Authentication tokens, API keys, or credentials you enter
|
||||
- Account information, email addresses, or names
|
||||
- Location data
|
||||
- Photos, microphone recordings, or camera data (these go only to your own server if you attach them to a message)
|
||||
- Contacts, calendar, or any other personal data
|
||||
|
||||
All communication between the app and your AI coding agent travels directly between your device and your self-hosted opencode server. VIBE TECHNOLOGIES, LLC never sees this traffic.
|
||||
|
||||
---
|
||||
|
||||
## 3. Data We Do Collect (Crash Diagnostics)
|
||||
|
||||
With your explicit consent (shown at first launch), we collect anonymous crash diagnostic data via **Sentry** to help us identify and fix bugs.
|
||||
|
||||
| Data type | What is captured | What is NOT captured |
|
||||
|---|---|---|
|
||||
| Device info | Device model, OS version, screen resolution, app version | Serial number, IMEI, advertising ID |
|
||||
| Crash / error reports | Stack traces, exception types and messages, source file names and line numbers | Variable values; no user data in scope |
|
||||
| Breadcrumbs | Screen names and function call sequence leading to the crash | Message bodies, server URLs, prompt text — all stripped by our URL-scrubbing filter |
|
||||
| App version | Version string and build number | — |
|
||||
|
||||
URL scrubbing: before any event is sent to Sentry, our code strips all server URLs, authentication tokens, and query parameters. No server hostname or port number ever leaves your device via Sentry.
|
||||
|
||||
---
|
||||
|
||||
## 4. Consent and Control
|
||||
|
||||
Crash reporting is **opt-in and off by default**. On first launch you will see a consent prompt. You can change this at any time:
|
||||
|
||||
- Open the app → **Settings** → **Privacy** → **Crash reporting** toggle.
|
||||
- When the toggle is off, Sentry is never initialised and no data leaves your device.
|
||||
|
||||
---
|
||||
|
||||
## 5. Third-Party Services
|
||||
|
||||
We use one third-party service for diagnostics:
|
||||
|
||||
- **Sentry** — crash and error monitoring.
|
||||
- Privacy policy: https://sentry.io/privacy/
|
||||
- Data is sent to Sentry's US-based servers and retained for approximately 90 days per Sentry's default data-retention policy.
|
||||
|
||||
We use no advertising networks, analytics platforms, social SDKs, or any other third-party data collection services. The app contains no ads and no ad SDKs.
|
||||
|
||||
---
|
||||
|
||||
## 6. Data Retention
|
||||
|
||||
Crash reports sent to Sentry are retained for approximately 90 days, after which they are automatically deleted per Sentry's retention defaults.
|
||||
|
||||
We do not operate our own servers that store your data; there is no VIBE TECHNOLOGIES back end involved in normal app usage.
|
||||
|
||||
---
|
||||
|
||||
## 7. Your Rights
|
||||
|
||||
You have the right to:
|
||||
|
||||
- **Opt out** — disable crash reporting at any time in Settings → Privacy.
|
||||
- **Request deletion** — email support@vibebrowser.app with subject "Data deletion request" and we will request deletion of any crash events associated with your device from Sentry.
|
||||
- **Access** — request a summary of what diagnostic data (if any) we hold about your device by emailing the same address.
|
||||
|
||||
Residents of the EU/EEA/UK may exercise rights under GDPR/UK GDPR. California residents may exercise rights under the CCPA.
|
||||
|
||||
---
|
||||
|
||||
## 8. Children
|
||||
|
||||
OpenCode Mobile is a developer tool intended for users aged 18 and over. We do not knowingly collect any data from children under 13 (or under 16 in the EU).
|
||||
|
||||
---
|
||||
|
||||
## 9. Security
|
||||
|
||||
All diagnostic data is transmitted over HTTPS (TLS 1.2+) to Sentry. We do not transmit any data over unencrypted connections.
|
||||
|
||||
---
|
||||
|
||||
## 10. Changes to This Policy
|
||||
|
||||
If we make material changes to this policy, we will update the effective date and, where feasible, notify users via an in-app notice. The latest version is always available at:
|
||||
https://www.vibebrowser.app/opencode-mobile/privacy
|
||||
|
||||
---
|
||||
|
||||
## 11. Contact
|
||||
|
||||
VIBE TECHNOLOGIES, LLC
|
||||
519 S Henderson St
|
||||
Seattle, WA 98108-4522
|
||||
USA
|
||||
Email: support@vibebrowser.app
|
||||
|
||||
---
|
||||
|
||||
## Apple-Specific Addendum (iOS / App Store)
|
||||
|
||||
This addendum addresses Apple's specific privacy disclosure requirements for iOS apps distributed through the Apple App Store.
|
||||
|
||||
### App Tracking Transparency (ATT)
|
||||
|
||||
OpenCode Mobile does **not** use Apple's App Tracking Transparency (`AppTrackingTransparency`) framework. The app does **not**:
|
||||
|
||||
- Access the IDFA (Identifier for Advertisers)
|
||||
- Use any cross-app or cross-website tracking
|
||||
- Participate in any advertising network
|
||||
- Profile users for advertising or marketing purposes
|
||||
|
||||
No ATT permission prompt is ever shown to users because there is nothing to track.
|
||||
|
||||
### Apple Privacy Nutrition Label Data Categories
|
||||
|
||||
The following table maps our data practices to Apple's official App Privacy categories (as required in App Store Connect):
|
||||
|
||||
| Apple Category | Sub-category | Collected? | Linked to identity? | Used for tracking? |
|
||||
|---|---|---|---|---|
|
||||
| Contact Info | Name, email, phone, address | No | N/A | No |
|
||||
| Health & Fitness | Any | No | N/A | No |
|
||||
| Financial Info | Any | No | N/A | No |
|
||||
| Location | Precise or coarse | No | N/A | No |
|
||||
| Sensitive Info | Any | No | N/A | No |
|
||||
| Contacts | Any | No | N/A | No |
|
||||
| User Content | Emails, messages, audio, gameplay, other | No | N/A | No |
|
||||
| Browsing History | Any | No | N/A | No |
|
||||
| Search History | Any | No | N/A | No |
|
||||
| Identifiers | User ID | No | N/A | No |
|
||||
| Identifiers | Device ID | Yes (Sentry anonymous ID) | No — not linked to Apple ID or personal info | No |
|
||||
| Purchases | Any | No | N/A | No |
|
||||
| Usage Data | Product interaction | No | N/A | No |
|
||||
| Diagnostics | Crash Data | Yes (Sentry, with consent) | No | No |
|
||||
| Diagnostics | Performance Data | Yes (Sentry, with consent) | No | No |
|
||||
| Diagnostics | Other Diagnostic Data | No | N/A | No |
|
||||
|
||||
**Summary for App Store Connect App Privacy section**:
|
||||
- Data Linked to You: **None**
|
||||
- Data Not Linked to You: **Crash Data, Performance Data** (Sentry diagnostics, when user consents)
|
||||
- Tracking: **No**
|
||||
161
distribution/strategy.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# OpenCode Mobile — Distribution + Monetization Strategy
|
||||
|
||||
Date: 2026-05-24
|
||||
Sources: 3 research reports (market analysis, monetization, F-Droid distribution) + Play Console signup state.
|
||||
|
||||
---
|
||||
|
||||
## Pick one model for everything downstream
|
||||
|
||||
**Free client everywhere + paid "opencode Cloud" hosted backend.**
|
||||
|
||||
Mirrors Tailscale ($45M ARR, OSS client, paid coordination service) and the opencode authors' own model (OSS CLI, paid OpenCode Zen gateway, several million ARR in 5 months).
|
||||
|
||||
- **Client (this repo, MIT)**: free on Play Store, IzzyOnDroid, and F-Droid. Identical binary on all three (same signing key via reproducible builds).
|
||||
- **opencode Cloud (separate product, proprietary)**: managed opencode server hosting. One-tap connect option in the app alongside "self-hosted" and "tunnel". Target $10/mo individual, $30/mo team. **Not built yet — see Action items.**
|
||||
- **Donations layer**: GitHub Sponsors / OpenCollective to cover Sentry + CI costs (~$60/mo) while cloud revenue scales.
|
||||
|
||||
Rejected alternatives:
|
||||
- ❌ **Paid Play + free F-Droid** — MIT allows redistribution; community resentment when users find F-Droid version; license-check callbacks always get stripped in forks. DAVx⁵ exception works only because it's a one-time donation, not a feature gate.
|
||||
- ❌ **Subscription gated in client** — telemetry license checks earn F-Droid `Tracking` anti-feature and instantly get stripped by community forks.
|
||||
- ❌ **Ads** — kills OSS credibility, contradicts a developer audience.
|
||||
|
||||
---
|
||||
|
||||
## Distribution channels — priority order
|
||||
|
||||
| # | Channel | Identity | Status | Time to live | Notes |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | **Google Play (Internal)** | `ai.opencode.mobile` | ⏸ blocked on identity verification | Days after ID approved | CI ready. Track: `internal` first, then closed testing (12+ testers / 14d) before production. |
|
||||
| 2 | **IzzyOnDroid** | `ai.opencode.mobile` (same key) | ❌ not started | 1–3 days | Submit prebuilt APK to https://codeberg.org/IzzyOnDroid/repodata/issues. Fastest OSS channel. |
|
||||
| 3 | **F-Droid mainline** | `ai.opencode.mobile` (same key, reproducible build) | ❌ not started | 4–12 weeks | File MR at https://gitlab.com/fdroid/fdroiddata. Requires `expo-notifications` FCM audit + Sentry opt-in gate. |
|
||||
| 4 | **Apple App Store** | `ai.opencode.mobile` | ⏸ pending iOS prep agent | Weeks (Apple enrollment $99 + review) | iOS agent running — separate report. |
|
||||
|
||||
**All channels: same package id (`ai.opencode.mobile`), same signing key.** Lets users update across stores in-place.
|
||||
|
||||
---
|
||||
|
||||
## Blockers + outstanding work
|
||||
|
||||
### Hard blockers (need user)
|
||||
|
||||
1. **Google Play identity verification** — upload governor ID (Dzianis Vashchuk). Unlocks: API access, Create app, AAB upload, CI publish.
|
||||
2. **Apple Developer Program enrollment** — $99/year, D-U-N-S 142059652 ready. iOS agent will produce runbook.
|
||||
3. **App icon + adaptive icon + feature graphic** — current `assets/*.json` are placeholders. Need real PNGs before either Play or App Store publish.
|
||||
4. **Privacy policy URL** — must be live at https://opencode.vibebrowser.app/privacy before Play publish. Template in `play-listing.md`.
|
||||
|
||||
### Soft blockers (we can fix without user)
|
||||
|
||||
5. **Sentry opt-in consent gate** — currently always-on; needed for F-Droid `Tracking` anti-feature avoidance. Add settings toggle + first-launch consent screen. Persist in `expo-secure-store`.
|
||||
6. ~~**Audit `expo-notifications` FCM usage**~~ — ✅ done 2026-05-24. `src/lib/notifications.ts` uses local-only (`scheduleNotificationAsync`); no `getExpoPushTokenAsync`/`getDevicePushTokenAsync` anywhere. Remaining concern: library still compiles FCM receiver classes — F-Droid scanner may flag. Fix later with a `fdroid` Gradle flavor that excludes the FCM artifact. **Non-blocker for IzzyOnDroid** (more tolerant). For mainline F-Droid: add `productFlavors { fdroid { /* exclude FCM */ } }` to `android/app/build.gradle`.
|
||||
7. **APK size check** — IzzyOnDroid limit 30 MB. AAB currently 58.5 MB but that's universal — per-ABI splits typically 15–20 MB.
|
||||
8. **Fastlane metadata** — `fastlane/metadata/android/en-US/{short_description.txt,full_description.txt,images/}` so F-Droid auto-pulls listing.
|
||||
9. **Reproducible build verification** — F-Droid builds from source, compares to our signed APK. Need to verify our build is reproducible (no embedded timestamps, no machine-specific paths).
|
||||
|
||||
### Pre-launch tasks (low priority, optional)
|
||||
|
||||
10. **opencode Cloud MVP** — managed opencode hosting service. Stripe billing. The actual revenue product. **Big scope, separate project.**
|
||||
11. **GitHub Sponsors profile** — VIBE TECHNOLOGIES, LLC org. Tiers: $5 / $15 / $50.
|
||||
12. **Closed testing tester recruitment** — 12+ testers for 14d before production. Recruit from opencode community / dev Twitter / r/androiddev.
|
||||
|
||||
---
|
||||
|
||||
## What's already done (this session)
|
||||
|
||||
| Item | Status |
|
||||
|---|---|
|
||||
| Google Play developer account (org) | ✅ Created, ID 8842655543970815326, $25 paid |
|
||||
| Mercury virtual card | ✅ Saved to Bitwarden |
|
||||
| D-U-N-S 142059652 | ✅ Retrieved, saved to Bitwarden + skill |
|
||||
| GCP project `opencode-mobile-deploy` | ✅ Created |
|
||||
| androidpublisher API | ✅ Enabled |
|
||||
| Service account `playstore-deploy@…` | ✅ Created, JSON key saved to Bitwarden + GitHub secret |
|
||||
| Signed AAB | ✅ Built at `android/app/build/outputs/bundle/release/app-release.aab` (58.5 MB) |
|
||||
| Website verification | ✅ www.vibebrowser.app verified via Search Console auto-detection |
|
||||
| Contact email verification | ✅ support@vibebrowser.app verified via Play Console code |
|
||||
| Payments profile | ✅ Linked with D-U-N-S 142059652 |
|
||||
| CI workflow audit + fixes | ✅ `publish-play-store.yml` — versionCode auto-bump, r0adkll@v1.1.5, whatsNewDirectory wired |
|
||||
| Play Store listing copy | ✅ `distribution/play-listing.md` |
|
||||
| Skill `vibetechnologies-llc` | ✅ Created with company facts |
|
||||
| Subagent `vibetechnologies-llc-curator` | ✅ Created for auto-maintenance |
|
||||
|
||||
---
|
||||
|
||||
## Per-channel publishing recipe
|
||||
|
||||
### Google Play (after identity verified)
|
||||
|
||||
1. (manual, in browser) Home → Verify your identity → upload governor ID. Wait days.
|
||||
2. (manual) Setup → API access → Link `opencode-mobile-deploy`. Grant `playstore-deploy@…` "Release to production".
|
||||
3. (manual) Create app `ai.opencode.mobile`. Fill listing from `play-listing.md`. Upload icon + feature graphic + screenshots. Complete Data safety + Content rating + App access.
|
||||
4. (manual, first time) Upload `app-release.aab` to Internal testing track. Add tester emails.
|
||||
5. (automated thereafter) `git tag v0.2.4 && git push --tags` → CI builds + publishes to Internal.
|
||||
|
||||
### IzzyOnDroid (after first Play AAB exists for parity)
|
||||
|
||||
1. Tag GitHub release `v0.2.x` with signed universal APK attached (not AAB — APK).
|
||||
2. File issue at https://codeberg.org/IzzyOnDroid/repodata/issues:
|
||||
```
|
||||
App name: OpenCode Mobile
|
||||
Package: ai.opencode.mobile
|
||||
License: MIT
|
||||
GitHub release: https://github.com/dzianisv/opencode-mobile/releases
|
||||
APK SHA-256: <sha256>
|
||||
Description: Mobile client for the opencode AI coding agent CLI. Self-hosted backend.
|
||||
Note: NonFreeNet anti-feature applies (connects to user-self-hosted opencode server).
|
||||
```
|
||||
3. Wait 1–3 days for inclusion. Updates auto-pulled from each new GitHub release tag.
|
||||
|
||||
### F-Droid mainline (after Sentry opt-in + FCM audit done)
|
||||
|
||||
1. Fork https://gitlab.com/fdroid/fdroiddata.
|
||||
2. Create `metadata/ai.opencode.mobile.yml` with reproducible-build config (template in F-Droid report).
|
||||
3. Set `AllowedAPKSigningKeys: <sha256-fingerprint>` so F-Droid serves our pre-signed APK.
|
||||
4. File MR. Iterate on build failures with reviewers. 4–12 week timeline.
|
||||
5. Once accepted, request IzzyOnDroid delisting (they auto-remove when mainline accepts).
|
||||
|
||||
### Apple App Store
|
||||
|
||||
Per iOS agent report (pending) — runbook at `distribution/ios-enrollment-runbook.md` (to be created).
|
||||
|
||||
---
|
||||
|
||||
## Trigger for auto-publish (item 3 from user's plan)
|
||||
|
||||
"As soon as we get the ability to publish" = identity verified + app created + first manual AAB uploaded.
|
||||
|
||||
Once those manual steps are complete:
|
||||
|
||||
- Tag `v0.2.4` (or whatever the next version is) → existing `publish-play-store.yml` CI runs:
|
||||
- Bumps `android.versionCode` from `github.run_number`
|
||||
- Builds signed AAB
|
||||
- Uploads to Internal track with what's-new notes
|
||||
|
||||
No additional infrastructure needed — CI is already wired for this. Just push the tag.
|
||||
|
||||
For email notification when Google approves identity: Google sends to vibeteaichnologies@gmail.com. Add a `gws gmail` poll script that watches for "Developer account verification" subject from `noreply@google.com` and pings via webhook / posts a GitHub issue.
|
||||
|
||||
---
|
||||
|
||||
## Files in this repo related to distribution
|
||||
|
||||
```
|
||||
distribution/
|
||||
├── PLAY_CONSOLE_SETUP.md # original handoff doc (now mostly historical)
|
||||
├── play-listing.md # full Play Store copy + answers
|
||||
├── strategy.md # this file
|
||||
├── whatsnew/
|
||||
│ └── whatsnew-en-US # release notes consumed by CI per-release
|
||||
└── (pending)
|
||||
├── app-store-listing.md # iOS agent will create
|
||||
├── ios-enrollment-runbook.md # iOS agent will create
|
||||
└── whatsnew-ios/
|
||||
└── release-notes-en-US.txt # iOS first release notes
|
||||
|
||||
.github/workflows/
|
||||
├── build.yml # Android dev build CI
|
||||
├── cua-smoke.yml # CUA smoke tests
|
||||
├── publish-play-store.yml # AUTOMATED Play publish on tag/release
|
||||
└── (pending)
|
||||
└── publish-app-store.yml # iOS agent will draft
|
||||
```
|
||||
36
distribution/whatsnew-ios/release-notes-en-US.txt
Normal file
@@ -0,0 +1,36 @@
|
||||
Welcome to OpenCode for iOS — v0.2.3
|
||||
|
||||
OpenCode is a mobile companion for the opencode AI coding agent (github.com/sst/opencode). This first release brings full remote-control of your self-hosted opencode server from iPhone and iPad.
|
||||
|
||||
WHAT'S IN THIS RELEASE
|
||||
|
||||
• Connect to any opencode server — local Wi-Fi (LAN), Cloudflare Tunnel, ngrok, Tailscale, or any HTTPS endpoint
|
||||
• Multiple saved connections — switch between workstations with one tap
|
||||
• Real-time streaming chat — watch your AI agent think and respond live as it codes
|
||||
• File diff viewer — review exact code changes the agent proposes before accepting
|
||||
• Tool call approvals — confirm file writes, shell commands, and other actions before execution
|
||||
• Multi-session management — start, resume, and switch between concurrent coding sessions
|
||||
• Face ID / Touch ID biometric unlock — keep your sessions private
|
||||
• Markdown rendering with syntax-highlighted code blocks
|
||||
• Image attachments — attach screenshots or diagrams to guide the agent
|
||||
• Voice input — dictate prompts hands-free via speech recognition
|
||||
• Dark mode optimized UI
|
||||
|
||||
GETTING STARTED
|
||||
|
||||
You need an opencode server to use this app:
|
||||
|
||||
npm install -g opencode-ai
|
||||
opencode serve
|
||||
|
||||
The terminal prints a URL (e.g. http://192.168.1.100:4096). Tap "Add Connection" in the app and enter that URL.
|
||||
|
||||
For remote access from outside your network, use Tailscale or Cloudflare Tunnel to expose the server securely.
|
||||
|
||||
OPEN SOURCE
|
||||
|
||||
MIT licensed. Source + issues: https://github.com/dzianisv/opencode-mobile
|
||||
|
||||
FEEDBACK
|
||||
|
||||
Please use the TestFlight feedback button or email support@vibebrowser.app. We read every report.
|
||||
6
distribution/whatsnew/whatsnew-en-US
Normal file
@@ -0,0 +1,6 @@
|
||||
Initial Internal testing release.
|
||||
|
||||
- Connect to your self-hosted opencode server (HTTP)
|
||||
- Drive AI coding sessions from your phone
|
||||
- Streaming chat, diffs, file tree
|
||||
- Crash reporting via Sentry
|
||||