A device runtime
Boots simulators and emulators, installs any .app or .apk, streams the screen, takes input, reads the accessibility tree, and collects screenshots, logs and crashes.
Troupe boots iOS Simulators and Android Emulators, streams their screens, drives them and tests the apps on them. On your own Mac with no account, or hosted in Troupe Cloud.
What is in the box
A device is a session with one lifecycle, one way to send input and one picture, whoever is driving: a test, a person in a browser, or a coding agent.
Boots simulators and emulators, installs any .app or .apk, streams the screen, takes input, reads the accessibility tree, and collects screenshots, logs and crashes.
test() and expect(), auto-waiting locators, retrying assertions, fixtures, projects and parallel workers. If you know Playwright, you know this.
Every action with its timing and a screenshot, the accessibility tree at the failure and the device's logs, in a viewer you can scrub.
The studio and the React components show a device as live video you can drive. The delay is 17 to 34 ms glass to glass at the median, measured on one Mac.
Every operation is one of 64 procedures, served over REST, RPC and MCP from a single local listener, with a typed client for your own tools.
31 curated MCP tools let a coding agent start a device, read the screen, tap, type and take a screenshot of the app it is building.
The test framework
Specs are *.e2e.ts files. Each worker holds one device and drives it with locators that wait and assertions that retry, so a test says what a person does and nothing about timing.
1import { expect, test } from '@alivelabs/troupe'
2
3test('signs in', async ({ screen }) => {
4 await screen.getByLabel('Email').fill('ada@example.com')
5 await screen.getByLabel('Password').fill('correct horse')
6 await screen.getByRole('button', { name: 'Sign in' }).tap()
7
8 await expect(screen.getByText('Welcome back')).toBeVisible()
9})
1import { defineConfig } from '@alivelabs/troupe'
2
3export default defineConfig({
4 retries: 1,
5 projects: [
6 {
7 name: 'ios',
8 use: {
9 platform: 'ios',
10 deviceType: 'iPhone 18 Pro',
11 app: './build/Shop.app',
12 },
13 },
14 {
15 name: 'android',
16 use: { platform: 'android', app: './build/shop.apk' },
17 },
18 ],
19})
bunx troupe test Running 3 tests using 1 worker ✓ 1 [ios] › e2e/sign-in.e2e.ts:3:1 › signs in ✓ 2 [ios] › e2e/cart.e2e.ts:3:1 › adds an item to the cart ✓ 3 [ios] › e2e/cart.e2e.ts:12:1 › checks out 3 passed
Studio and components
troupe studio opens a device you can watch and drive, with its accessibility tree and logs beside it. The same pieces ship as React components, so the device can live in your own page.
1import { createClient } from '@alivelabs/troupe-client'
2import {
3 DeviceScreen,
4 TroupeProvider,
5} from '@alivelabs/troupe-react'
6import '@alivelabs/troupe-react/styles.css'
7
8const client = createClient({ baseUrl, token })
9const getTicket = (cap = 'drive') =>
10 client.call('streams.ticket', { sessionId, cap })
11
12<TroupeProvider client={client}>
13 <DeviceScreen stream={{ url, ticket }} getTicket={getTicket} />
14</TroupeProvider>
The React components MCP
An agent that can see the app it is building stops guessing. troupe mcp serves the runtime as MCP tools: start a device, install the build, read the screen, tap, type, take a screenshot, read the logs.
bunx troupe mcp install --client claude-code --writeWrites the project's MCP entry for Claude Code, Cursor, VS Code or Codex. Nothing leaves your Mac.
Connecting an agentsessions_createiPhone 18 Pro, ios-simulatorapps_installShop.appapps_launchcom.example.shopui_snapshotthe accessibility treeinput_tapbutton "Add to cart"media_screenshotwhat the screen shows nowTroupe Cloud
Devices and builds for a team, without a Mac under anyone's desk. The API is the one you already use locally, with accounts, projects and limits around it.
Devices in a tab
Start an iOS or Android device and watch or drive it from the browser, the client or an agent.
Builds from a repository
Expo and Xcode projects, from a git ref or an upload, with their logs and artifacts.
Organizations and projects
Members with roles, projects that own the work, and limits you can see.
API keys with scopes
Keys that belong to the organization, expire, and can be held to one project.
CI without stored secrets
Exchange a short-lived token from GitHub Actions for one that is good for a single project.
Sharded test runssoon
One suite split across devices in the cloud.
Platforms
Troupe runs on a Mac with Apple silicon and brings its own drivers and media engines for each platform.
Any simulator your Xcode offers, with live video and touch.
simctl · XCUITest driver · simcap
Emulators behind Troupe's own adb server, out of the way of yours.
adb wire client · instrumentation driver · scrcpy
Prebuilt Catalyst apps, driven from inside their own process.
Troupe's host, linked into the app
Open source
The runtime, the test framework, the client, the React components, the studio and the report are MIT licensed. The repository opens soon; until then the docs describe everything as it will ship.
@alivelabs/troupe@alivelabs/troupe-runtime@alivelabs/troupe-protocol@alivelabs/troupe-client@alivelabs/troupe-react@alivelabs/troupe-report@alivelabs/troupe-platform-ios@alivelabs/troupe-platform-android@alivelabs/troupe-platform-catalyst@alivelabs/troupe-adapter-kit@alivelabs/troupe-preset-expo