opencode-mobile
AGENTS.md295 starsChanged 4 months agoMITView on GitHub
See .agents/retro.md for lessons from past tasks. Read entries related to your current work before starting — they document mistakes that cost hours and how to avoid them. Failure taxonomy — classify every failure before acting. Escalate cheapest-first; never skip a rung or repeat one: - transient (network blip, flaky): retry at most 2×. - code (your bug, wrong path, bad arg): fix, then retry. - tool-usage-gated (you called a working tool wrong): fix the call, not the tool. Cheapest…
- Reads credentials
- Installs packages
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,774 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository6 other files it gives its agents.
The file
Show its rules and text
We split this AGENTS.md into the rules it gives an agent
20 rules. About 0 are common, 7 are distinctive, and 13 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈7
Distinctive · estimate
This author's own choices. Worth a look.
13
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Distinctive: line 17
Diagnose before fixing: Before patching or replacing any tool, confirm it is actually the cause.
- Very specific: line 70
Prefer const over let
- Very specific: line 71
Avoid else statements, use early returns
- Distinctive: line 72
Prefer single-word variable names
- Very specific: line 73
Avoid try/catch where possible
- Distinctive: line 75
Use Bun APIs where applicable (for scripts, not in RN runtime)
- Very specific: line 87
Run opencode serve --hostname 0.0.0.0 --port 4096 on your machine, then add a connection in the app with your machine's local IP and port …
- Very specific: line 153
Use --e2e-model-hint deepseek to select deepseek-v4-flash-free (free quota, good for coding tasks).
- Very specific: line 166
Use max_completion_tokens (NOT max_tokens) — the older param is rejected.
- Very specific: line 167
Use AzureOpenAI client from the openai Python SDK with api_version="2024-08-01-preview".
- Distinctive: line 185
MANDATORY: Run the CUA smoke test before any merge to main or release:
- Very specific: line 186
Before merging a PR that touches src/, app/, or scripts/android-cua-smoke.py
- Distinctive: line 187
After creating a release tag — CI runs it automatically
- Very specific: line 188
When debugging UI issues — run locally with --include-xml for richer context
- Very specific: line 189
When validating a specific AI coding task — use --e2e or --query
- Distinctive: line 191
If the CUA test fails, do NOT merge or release until fixed.
- Very specific: line 195
All project secrets are stored in Bitwarden vault under folder opencode-mobile.
- Very specific: line 197
Use the bitwarden-cli skill to read/write secrets.
- Very specific: line 225
Use @vibebrowser/cli against the authenticated remote browser relay.
- Distinctive: line 228
Keep the relay URL outside the repository:
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Mobile App - AGENTS.md
Retrospectives (read before related work)
See .agents/retro.md for lessons from past tasks. Read entries related to your current work before starting — they document mistakes that cost hours and how to avoid them.
Agent Operating Rules (read first)
Failure taxonomy — classify every failure before acting. Escalate cheapest-first; never skip a rung or repeat one:
- transient (network blip, flaky): retry at most 2×.
- code (your bug, wrong path, bad arg): fix, then retry.
- tool-usage-gated (you called a working tool wrong): fix the call, not the tool. Cheapest fix — try this before assuming the tool is broken. Example: chrome-devtools
new_pagewithisolatedContextopens a cookieless context; instead uselist_pages→select_pageto drive the existing authenticated tab. - tooling-gated (the tool's source is genuinely broken): diagnose before fixing — verify it's actually broken (read the code, reproduce). If broken, spawn a fix-it subagent to patch + rebuild it, then retry. Do NOT stop.
- infra (CI runner, emulator boot timeout): report it; do not try to "fix" someone else's infrastructure.
- human-gated (only when no automated path exists): emit ONE precise instruction for the human, mark the task BLOCKED, and continue all other automatable work. Never re-attempt across turns.
Diagnose before fixing: Before patching or replacing any tool, confirm it is actually the cause. Copilot burned 39h assuming chrome-devtools-mcp was broken — it wasn't (it already drives the authenticated default context via browser.defaultBrowserContext()/browser.pages()). A 3-minute diagnostic subagent would have caught this.
Known gated steps:
- Play Console API-access grant to the service account — was the blocker; now granted (publish run 26662900471 succeeded, AAB on internal track, versionCode 19). One-time path if re-needed: Play Console → Setup → API access → link GCP project
opencode-mobile-deploy→ grantplaystore-deploy@opencode-mobile-deploy.iam.gserviceaccount.comAdmin/Release-manager. - Add internal testers (Play Console → Internal testing → Testers): the genuinely human-gated residual. Google's anti-automation blocks CDP-controlled Chrome sign-in, so this UI step needs a human (or a real, non-CDP browser session).
Stop discipline: If a tool returns the same error 3× (or no new artifact/commit is produced across several turns), STOP. Print a BLOCKED summary with the single human action needed. A vague "please do X and let me know" that leaves you idle is worse than a clean stop — don't do it.
Work-tracking discipline:
- Track multi-step/upgrade work in the related GitHub issue, updated via
gh issue comment— NOT by repeatedly editing AGENTS.md and NOT in scratch files under/tmp(e.g. no/tmp/playconsole-fill.md). Keep reference material (listing copy, form answers) in the repo underdistribution/or as issue comments. - AGENTS.md is for durable conventions only; do not churn it with task status.
- Never claim a step done without verifying it in the real channel (e.g. an app exists only if it appears in the Play Console app-list; an AAB is the right package only if its manifest says so). Do not invent IDs.
- Driving web UIs: snapshot → act on the current uids → re-snapshot. Never fire batched/guessed clicks; if a page shows "Loading"/an error toast, wait and re-snapshot rather than clicking blind.
Overview
React Native / Expo mobile client for opencode. Connects to an opencode server instance via HTTP + SSE for real-time updates.
Repo: dzianisv/opencode-mobile (standalone, not part of opencode monorepo)
Package name: cc.agentlabs.opencode
Architecture
app/ # Expo Router file-based routing
├── (tabs)/ # Tab navigation (sessions, connections, settings)
├── session/[id].tsx # Chat screen
└── connection/ # Add/edit connection screens
src/
├── components/ # Reusable UI components
│ ├── markdown/ # Markdown renderer (wraps react-native-marked)
│ └── AuthGate.tsx # Biometric auth gate
├── lib/
│ ├── sdk.ts # HTTP + SSE client for opencode server API
│ └── types.ts # Re-exported types
└── stores/ # Zustand state stores
├── sessions.ts # Session list, messages, parts
├── connections.ts # Server connections, client lifecycle
├── events.ts # SSE event stream, status tracking, permissions, questions
└── auth.ts # Biometric auth
scripts/
└── android-cua-smoke.py # LLM-powered CUA E2E testKey Patterns
- SSE for real-time: The
events.tsstore connects to/global/eventand dispatches to other stores - Fire-and-forget sends:
sendMessageposts to the API but doesn't await response; SSE events drive all UI updates - Session status: Derived from
session.statusevents (idle/busy/retry) + last part type for status text - Markdown:
react-native-markedwrapped in our ownMarkdowncomponent with customCodeBlock(copy button). Designed to be swappable/publishable later.
Style Guide
- Prefer
constoverlet - Avoid
elsestatements, use early returns - Prefer single-word variable names
- Avoid
try/catchwhere possible - Avoid
anytype - Use Bun APIs where applicable (for scripts, not in RN runtime)
Running
npm install
npx expo start # Expo dev server
npx expo run:android # Android emulatorConnecting
Run opencode serve --hostname 0.0.0.0 --port 4096 on your machine, then add a connection in the app with your machine's local IP and port 4096.
Dev server: 100.108.64.76:4096 (Tailscale, hostname openclaw-dev-1)
Android Emulator (local dev)
IMPORTANT: Do NOT install SDK/AVD on the system disk. Use the external disk.
export ANDROID_HOME=/Volumes/Dzianis-3/macbook2020/android-sdk
export ANDROID_AVD_HOME=/Volumes/Dzianis-3/macbook2020/android-avd
export GRADLE_USER_HOME=/Volumes/Dzianis-3/macbook2020/gradle-cache
export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator:$PATH"
emulator -avd test -no-window -no-audio -no-boot-anim -gpu swiftshader_indirect -no-snapshot -port 5554
adb wait-for-device
# Wait for boot:
timeout 120 bash -c 'while [ "$(adb shell getprop sys.boot_completed 2>/dev/null)" != "1" ]; do sleep 2; done'SDK location: /Volumes/Dzianis-3/macbook2020/android-sdk (API 34, arm64-v8a system image).
AVD location: /Volumes/Dzianis-3/macbook2020/android-avd.
Gradle cache: /Volumes/Dzianis-3/macbook2020/gradle-cache (or symlink from /Volumes/GradleCache/gradle-home).
CUA Smoke Test (E2E via Vision LLM)
The script scripts/android-cua-smoke.py drives the emulator via ADB using a vision model loop (screenshot → LLM → action → repeat).
Run modes
--showcase (default, regression guard)
source ~/.env.d/azure-openai.env
python3 scripts/android-cua-smoke.py --model gpt-5.4 --include-xmlRuns: connect → sessions load (pre-created session MUST appear) → new session → sessions reload → TypeScript task → settings.
--e2e (full coding task, project dir, model picker)
source ~/.env.d/azure-openai.env
python3 scripts/android-cua-smoke.py --e2e \
--opencode-url http://100.108.64.76:4096 \
--e2e-project-dir ~/workspace/opencode-mobile \
--e2e-model-hint deepseek \
--e2e-task "Write a hello_world.py file that prints 'Hello World' to stdout." \
--e2e-filename hello_world.pyPhases: connect → long-press FAB → enter project dir → select deepseek model → submit task → DETERMINISTIC API poll for idle → DETERMINISTIC API scan for filename → DETERMINISTIC ADB uiautomator check.
--query (natural-language test description)
source ~/.env.d/azure-openai.env
python3 scripts/android-cua-smoke.py \
--opencode-url http://100.108.64.76:4096 \
--query "Open android app. Setup against remote opencode server. Go to sessions. \
Open a new project inside ~/workspace/opencode-mobile. \
Choose opencode/deepseek model. Start a new session. \
Ask to write hello_world.py. Validate that agent completed task." \
--eval-output /tmp/eval-report.jsonThe LLM plans phases from the query, executes them, runs deterministic checks, and prints a scored evaluation report (overall/score/phases/recommendations).
Available models on dev server (100.108.64.76:4096)
Key models: deepseek-v4-flash-free (opencode), claude-fable-5 (anthropic), gpt-5.4 (github-copilot), gemini-3.5-flash (github-copilot)
Use --e2e-model-hint deepseek to select deepseek-v4-flash-free (free quota, good for coding tasks).
Azure OpenAI credentials
The correct Azure AI Services endpoint (with actual deployments) is:
- Endpoint:
https://info-mjnxtt51-eastus2.cognitiveservices.azure.com - Env file:
~/.env.d/azure-openai.env - Available vision models:
gpt-5.4,gpt-5.2,gpt-5.1,gpt-4.1
WARNING: The
vibe-dev-ai.cognitiveservices.azure.comresource has NO deployments (only a model catalog). Do NOT use it for inference. Always useinfo-mjnxtt51-eastus2.
API notes for gpt-5.x models
- Use
max_completion_tokens(NOTmax_tokens) — the older param is rejected. - Use
AzureOpenAIclient from theopenaiPython SDK withapi_version="2024-08-01-preview". - Vision works: pass
image_urlwithdata:image/png;base64,...in user message content array.
CI
GitHub Actions workflow: .github/workflows/cua-smoke.yml
Secrets required: AZURE_OPENAI_API_KEY, AZURE_OPENAI_ENDPOINT (already set on dzianisv/opencode-mobile).
Triggers: Runs on push to main (with path filters) AND on v* tags (releases).
Dispatch inputs (workflow_dispatch):
scenario:showcase(default) |e2equery: natural-language test description (enables--querymode, overrides scenario)opencode_url: override server URL (use Tailscale URL for live server)e2e_project_dir,e2e_model_hint,e2e_task,e2e_filename: e2e mode params
When to run CUA test
MANDATORY: Run the CUA smoke test before any merge to main or release:
- Before merging a PR that touches
src/**,app/**, orscripts/android-cua-smoke.py - After creating a release tag — CI runs it automatically
- When debugging UI issues — run locally with
--include-xmlfor richer context - When validating a specific AI coding task — use
--e2eor--query
If the CUA test fails, do NOT merge or release until fixed.
Secrets Management
All project secrets are stored in Bitwarden vault under folder opencode-mobile.
Use the bitwarden-cli skill to read/write secrets. Quick reference:
# Unlock (needs BW_PASSWORD in env or ~/.bitwarden_credentials)
source ~/.bitwarden_credentials
export BW_SESSION=$(bw unlock --passwordenv BW_PASSWORD --raw)
bw sync --session "$BW_SESSION"
# Get a secret
bw get notes "EXPO_PUBLIC_SENTRY_DSN" --session "$BW_SESSION"
# List all secrets in the folder
FOLDER_ID=$(bw list folders --session "$BW_SESSION" | jq -r '.[] | select(.name=="opencode-mobile") | .id')
bw list items --session "$BW_SESSION" | jq --arg f "$FOLDER_ID" '[.[] | select(.folderId==$f) | {name}]'Secrets stored in vault:
EXPO_PUBLIC_SENTRY_DSN— Sentry ingest DSN (embedded in APK at build time)SENTRY_AUTH_TOKEN— sentry-cli upload token (source maps, releases)SENTRY_ORG—vibetechnologiesSENTRY_PROJECT—opencode-mobile
These same secrets are set as GitHub Actions secrets on dzianisv/opencode-mobile for CI builds.
Do NOT store secrets in .env files committed to the repo. .env is gitignored — local copy only.
VibeBrowser CLI (Browser Automation)
Use @vibebrowser/cli against the authenticated remote browser relay. Do not
register or use the retired chrome-devtools MCP server in Copilot.
Keep the relay URL outside the repository:
export VIBEBROWSER_REMOTE_URL='wss://relay.api.vibebrowser.app/<session-id>'
npx -y @vibebrowser/cli@0.2.12 \
--remote "$VIBEBROWSER_REMOTE_URL" --json statusList tabs first, then pass --page-id on every command so automation does not
switch or disturb the user's active tab:
npx -y @vibebrowser/cli@0.2.12 \
--remote "$VIBEBROWSER_REMOTE_URL" --json tabs
npx -y @vibebrowser/cli@0.2.12 \
--remote "$VIBEBROWSER_REMOTE_URL" --page-id <id> --json snapshotGitHub Auth
For pushes/gh CLI on this repo: source ~/.env.d/github-dzianisv.env
Google Account
ALL Google operations (Play Console, GCP Console, YouTube, Firebase, etc.) use vibeteaichnologies@gmail.com — the VIBE TECHNOLOGIES, LLC account. dzianisvv@gmail.com is the personal account and does NOT have access to the project GCP resources, Play Console, or YouTube channel. Always verify the active account in the top-right corner before making changes. If GCP console shows dzianisvv@gmail.com, switch accounts via the avatar menu.
Google Play Console
- Developer account: VIBE TECHNOLOGIES, LLC (ID:
8842655543970815326), Google loginvibeteaichnologies@gmail.com. The/u/N/index is NOT stable — if a console URL bounces to accept-terms/create-developer-account you're on the wrong Google account (e.g.dzianisvv@gmail.comhits a ToS gate); use the developer-account chooser to reach VIBE. - Rebrand (2026-05-30): package renamed
ai.opencode.mobile→cc.agentlabs.opencode. App IS live on Play Store internal track (v0.4.6, versionCode 33). CI publishes updates automatically via the service account after the first manual upload was completed. CIpackageName=cc.agentlabs.opencode. NOTE: CI publish build needs the "Purge stale generated sources" step (commit 67e4c1f) or cached old-package autolinking breaks compile. - Legacy app (orphaned):
ai.opencode.mobile, app ID4975545755653045321— published v19 to internal track (run 26662900471), superseded by the rebrand. - Track: Internal testing (no review required, up to 100 testers)
- Service account:
playstore-deploy@opencode-mobile-deploy.iam.gserviceaccount.com(account-level API access already granted)
Related Issues
- Upstream:
anomalyco/opencode#10288 - Branch on upstream fork:
feat/android-backbone-10288ondzianisv/opencode
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

