Cofounder CLI
Mobile Apps
Develop, test, build, and ship Expo mobile apps with EAS: previews, Maestro tests, store submissions, and over-the-air updates.
cofounder mobile runs an Expo (React Native) app's lifecycle on Expo
Application Services (EAS): installable previews, Android and iOS builds,
Maestro tests on emulators and simulators, TestFlight and Google Play
submissions, and over-the-air (OTA) updates. The commands run the pinned eas
CLI in a local app checkout, so EAS builds exactly the source you have. Every
command takes --dir <app directory> (default: the current directory) and
--json for structured results.
| MCP | CLI | API |
|---|---|---|
| — | cofounder mobile init | POST /cofounder-cli/v1/company/mobile/projects, POST /cofounder-cli/v1/company/mobile/projects/provision |
| — | cofounder mobile status | GET /cofounder-cli/v1/company/mobile/jobs, GET /cofounder-cli/v1/company/mobile/jobs/{job_id} |
| — | — | GET /cofounder-cli/v1/company/mobile/project, POST /cofounder-cli/v1/company/mobile/credentials, POST /cofounder-cli/v1/company/mobile/jobs, POST /cofounder-cli/v1/company/mobile/jobs/{job_id}/provider, POST /cofounder-cli/v1/company/mobile/jobs/{job_id}/outcome |
The job and credential routes support the commands: each build, submission, update, rollback, and test is recorded as a Cofounder job keyed by its intent, so rerunning an interrupted command reuses the operation it already started.
Set up the app
init scaffolds or connects an Expo app and configures EAS for it. A new
app's EAS project is created in the company's Cofounder-managed Expo
organization, so no Expo account or login is needed; pass --account, or an
Expo access token with --expo-token-stdin, to use your own Expo account
instead. It writes eas.json profiles (development, development-simulator,
simulator, preview, production; submit: beta, production), update
channels, and Maestro wiring, and records the app on the company.
cofounder mobile init --create --dir apps/mobile \
--bundle-id com.example.app --api-url https://api.example.com --json
cofounder mobile init --dir apps/mobile --account my-expo-org --jsonDevelop
The inner loop runs JavaScript in a development build. Build one once per native change, then let Metro serve JavaScript changes without another build:
cofounder mobile dev start --dir apps/mobile --api-url https://api.example.com --tunnel --json
cofounder mobile dev status --dir apps/mobile --json
cofounder mobile dev logs --dir apps/mobile --lines 100
cofounder mobile dev stop --dir apps/mobiledev start runs Metro in the background and returns its URL, process id, and
log path; it reports the running server instead of starting a second one. With
--tunnel, Metro is also served at a public HTTPS URL for hosted simulators
and phones on other networks.
Remote simulator
cofounder mobile simulator start --dir apps/mobile --dev --max-minutes 30 --json
cofounder mobile simulator exec --dir apps/mobile -- npx agent-device@latest open com.example.app --platform ios
cofounder mobile simulator exec --dir apps/mobile -- npx agent-device@latest screenshot shot.png
cofounder mobile simulator status --dir apps/mobile --json
cofounder mobile simulator stop --dir apps/mobilesimulator start runs the app on a remote iOS simulator or Android emulator on
EAS (EAS Simulator, an Expo preview that the app's Expo account needs access
to). It installs the newest simulator build matching the source's native
fingerprint; --dev installs the development build and opens Metro's tunnel
from dev start --tunnel, so edits reach the device live. It returns the
session page and, on iOS, a live browser view. exec runs a controller
command, such as agent-device's snapshot, press, or screenshot, against
the session; agent-device acts on the app it opened, so open the app's bundle
id first. A session bills until it stops or reaches --max-minutes.
Preview and test
cofounder mobile preview --dir apps/mobile --simulator --wait 1800 --json
cofounder mobile preview --dir apps/mobile --platform android --json
cofounder mobile test --dir apps/mobile --flow .maestro --wait 1800 --jsonpreview builds the preview profile (device installs) or, with
--simulator, the simulator profile for automated tests. test runs
Maestro flows on EAS emulators and simulators and needs an EAS paid plan;
without --build, it picks the newest finished emulator or simulator build
matching the source's native fingerprint.
Build and submit
cofounder mobile build --dir apps/mobile --platform all --wait 3600 --json
cofounder mobile submit --dir apps/mobile --track beta --wait 1800 --json
cofounder mobile submit --dir apps/mobile --track production --platform ios --build <build-id> --jsonbuild uses the production profile unless you pass --profile. submit
sends the newest finished store build (or --build): --track beta uploads
to App Store Connect for TestFlight and to the Play internal testing track;
--track production uploads to App Store Connect and creates a draft Play
production release, so nothing goes live by itself.
Over-the-air updates
cofounder mobile update --dir apps/mobile --channel production --dry-run --json
cofounder mobile update --dir apps/mobile --channel production --message "Fix checkout copy" --json
cofounder mobile rollback --dir apps/mobile --channel production --jsonUpdates change JavaScript and assets only. update checks each platform's
native runtime fingerprint against finished builds on the channel and refuses
with ota_incompatible when a platform needs a new binary. rollback
republishes the channel's previous update, or returns devices to the embedded
bundle with --to-embedded.
Status and logs
cofounder mobile status --dir apps/mobile --json
cofounder mobile status --dir apps/mobile --job <job-id> --release --wait 600 --json
cofounder mobile logs --dir apps/mobile --job <job-id> --lines 200status reads unfinished jobs from EAS and records their outcome; --release
adds App Store Connect state for iOS submissions. Results carry stable error
codes such as expo_auth_required, eas_plan_required,
store_credentials_required, mobile_project_mismatch, and ota_incompatible.