diff --git a/AGENTS.md b/AGENTS.md index 611ba779..a7cdc140 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -189,6 +189,11 @@ actions, safety rules, or topic routing change. The static skill changes only when its activation description or single routing command changes. +When adding or changing a user-facing feature, update the affected website +pages under `website/docs/` and their command examples alongside the CLI guides. +Include a copyable agent prompt when it helps users try the feature. Keep +website behavior, flags, defaults, and limitations aligned with the implementation. + Document command invocation once in each human-facing installation entry point. Show the no-install form, `npx stim `, and the global install, `npm install --global stim`. The static skill is only a router and diff --git a/packages/stim-cli/src/__tests__/guide.test.ts b/packages/stim-cli/src/__tests__/guide.test.ts index d11b4ba3..4fed605c 100644 --- a/packages/stim-cli/src/__tests__/guide.test.ts +++ b/packages/stim-cli/src/__tests__/guide.test.ts @@ -474,11 +474,12 @@ test('the settings guide documents every configurable optimization', () => { } }); -test('EAS guidance routes agents to the profile and preserves the paid-build authorization boundary', () => { +test('EAS guidance requires profile clarification when needed and authorization for paid builds', () => { const agent = renderTopic('agent'); expect(agent).toContain('stim guide lifecycle eas'); const eas = renderSection('lifecycle', 'eas'); expect(eas).toContain('--eas-profile'); + expect(eas).toMatch(/no\s+compatible profile or the choice is ambiguous, ask the user/); expect(eas).toContain('fingerprint:generate uploads fingerprint metadata'); expect(eas).toMatch(/session authorizes the potentially billable/); expect(eas).toContain('STIM_EAS_BUILD_MISSING'); diff --git a/packages/stim-cli/src/guide/agent.ts b/packages/stim-cli/src/guide/agent.ts index 383abe4c..cab4454a 100644 --- a/packages/stim-cli/src/guide/agent.ts +++ b/packages/stim-cli/src/guide/agent.ts @@ -92,9 +92,10 @@ them. It preserves source, custom launcher settings, and the shared ccache. stim start stim ios # or: stim android -For a project using EAS development builds, select the agreed profile with +For a project using EAS development builds, read stim guide lifecycle eas to +select a profile from eas.json for the requested target, then run stim ios --eas-profile or stim android --eas-profile . -Read stim guide lifecycle eas before using this path. A miss stops with +Ask the user if the profile choice is ambiguous. A miss stops with STIM_EAS_BUILD_MISSING and an EAS build command. Run that command only when the session authorizes the potentially billable build, then retry Stim. The presence of eas.json does not select EAS or authorize building. diff --git a/packages/stim-cli/src/guide/lifecycle.ts b/packages/stim-cli/src/guide/lifecycle.ts index 028e8719..e03f3cc9 100644 --- a/packages/stim-cli/src/guide/lifecycle.ts +++ b/packages/stim-cli/src/guide/lifecycle.ts @@ -202,6 +202,15 @@ android.gradleCommand must be a single :app:assembleDebug task producin an APK. Install eas-cli and authenticate with eas login or EXPO_TOKEN. The Expo app must already be linked to the intended EAS project. +Use the profile the user names. Otherwise inspect eas.json, including extends +and platform overrides, for the requested platform, simulator or physical +device, and app variant or environment. Choose a profile only when those +requirements identify one compatible development profile. If there is no +compatible profile or the choice is ambiguous, ask the user. Profile names +alone do not establish compatibility. Confirm the resolved settings with +npx eas-cli config --platform --profile --json --non-interactive. +Pass the selected name to --eas-profile; the CLI does not infer it. + Stim delegates profile inheritance, environment resolution and fingerprinting to EAS CLI. fingerprint:generate uploads fingerprint metadata to EAS. It does not start a native build. EAS access is needed even when the artifact is diff --git a/website/docs/agent-skills.md b/website/docs/agent-skills.md index a47f641a..52c18e78 100644 --- a/website/docs/agent-skills.md +++ b/website/docs/agent-skills.md @@ -4,9 +4,13 @@ sidebar_position: 4 description: 'Install the small Stim workflow skill for coding agents' --- +:::note[Command examples] + Commands use `stim`. If it is not installed globally, replace `stim` with `npx stim`. +::: + Install the bundled skill from the repository: ```bash diff --git a/website/docs/android-cas.md b/website/docs/android-cas.md index 15e38d14..fd0ccb00 100644 --- a/website/docs/android-cas.md +++ b/website/docs/android-cas.md @@ -101,9 +101,15 @@ assertion failures stop the script. All fixture data remains available. ## Application integration After building the Stim checkout, use its CLI with a disposable React Native/Expo -worktree and a private `STIM_HOME`. Commands use `stim`; replace it with +worktree and a private `STIM_HOME`. + +:::note[Command examples] + +Commands use `stim`; replace it with `npx stim` if it is not installed globally. +::: + For persistent selection, merge this into `$STIM_HOME/config.json` (default `~/.stim/config.json`). The same `optimizations` object in `.stim.json` can override machine defaults per app when placed beside the app's `package.json`. diff --git a/website/docs/build-caches.md b/website/docs/build-caches.md index 415595e6..9e630536 100644 --- a/website/docs/build-caches.md +++ b/website/docs/build-caches.md @@ -6,9 +6,13 @@ description: 'How Stim keeps worktree builds warm' import StimTabs from '@site/src/components/StimTabs'; +:::note[Command examples] + Commands use `stim`. If it is not installed globally, replace `stim` with `npx stim`. +::: + Stim shares four types of work across projects and git worktrees: | Layer | What it avoids | diff --git a/website/docs/build-optimizations.md b/website/docs/build-optimizations.md index 2d1e2243..8c27d1fe 100644 --- a/website/docs/build-optimizations.md +++ b/website/docs/build-optimizations.md @@ -5,9 +5,13 @@ description: 'Control native artifact reuse, compiler caches, PCH, and Metro cac import StimTabs from '@site/src/components/StimTabs'; +:::note[Command examples] + Commands use `stim`. If it is not installed globally, replace `stim` with `npx stim`. +::: + Stim enables build optimizations by default. Use the `optimizations` settings to disable individual layers when debugging or to opt into experimental compiler caching. For an overview of the layers, see [build speed and caches](./build-caches.md). diff --git a/website/docs/cache-packages.md b/website/docs/cache-packages.md index ba134e3e..1738537b 100644 --- a/website/docs/cache-packages.md +++ b/website/docs/cache-packages.md @@ -4,9 +4,13 @@ sidebar_position: 5 description: 'Optional npm packages for builds that run outside Stim' --- +:::note[Command examples] + Commands use `stim`. If it is not installed globally, replace `stim` with `npx stim`. +::: + Stim supplies its own cache arguments when it runs Metro and native builds. A project does not need these packages for `stim start`, `stim ios`, or `stim android`. diff --git a/website/docs/commands.md b/website/docs/commands.md index 531f5525..d37797ec 100644 --- a/website/docs/commands.md +++ b/website/docs/commands.md @@ -6,9 +6,13 @@ description: 'Every Stim command and option' import StimTabs from '@site/src/components/StimTabs'; +:::note[Command examples] + Commands use `stim`. If Stim is not installed globally, replace `stim` with `npx stim`. +::: + Run `stim --help` for parser help. Run `stim guide` for the full reference that ships with the installed version. @@ -30,6 +34,15 @@ restarts it. Use it when an error screen remains after a fix, not after every JavaScript edit. It also recovers an Android app whose first bundle failed; an iOS app in that state never connects to Metro, so reload cannot reach it. +## Named device slots + +`ios`, `android`, `device lock`, `device unlock`, `logs`, and `stop` accept +`--slot `. Omitting it selects the default target for a device run; +plain `logs` and `stop` still cover the whole workspace. `status` lists every +slot. Slots can hold multiple simulators of the same model as well as physical +devices. See [multiple devices with slots](./owned-devices.md#multiple-devices-with-slots) +for commands, a copyable agent prompt, and shared-server limitations. + ## `doctor` ```text @@ -88,7 +101,7 @@ project is reused. ## `ios` ```text -stim ios [--scheme ] [--configuration ] [--device-type ] [--runtime ] +stim ios [--slot ] [--scheme ] [--configuration ] [--device-type ] [--runtime ] [--device [udid]] [--wait | --no-wait] [--remote ] [--eas-profile ] [--no-metro-check] [--no-build-cache] [--json] ``` @@ -166,7 +179,7 @@ into cached iOS physical-device builds. ## `android` ```text -stim android [--variant ] [--system-image ] [--device [serial]] +stim android [--slot ] [--variant ] [--system-image ] [--device [serial]] [--wait | --no-wait] [--remote ] [--eas-profile ] [--no-metro-check] [--no-build-cache] [--json] ``` @@ -258,7 +271,7 @@ device and inspect `stim logs --errors` before claiming recovery. ## `logs` ```text -stim logs [--source ] +stim logs [--slot ] [--source ] [--level ] [--since ] [--grep ] [--tail ] [--errors] [--follow] [--json] @@ -278,14 +291,17 @@ result. ## `stop` ```text -stim stop [--json] +stim stop [--slot ] [--json] ``` -Stops the supervisor and log collectors. It shuts down the owned local device, -ends an owned remote session, and frees the port. A local device stays assigned -for reuse. An external server on the reserved port is left running, and a +Without `--slot`, stops the supervisor and all log collectors, shuts down every +owned local device, ends an owned remote session, and frees the port. Owned +local devices stay assigned for reuse. An external server on the reserved port is left running, and a process whose ownership cannot be verified is not signalled. +With `--slot `, stops only that slot's owned devices and collectors and +releases its leases. Metro, the reserved port, and sibling slots keep running. + On a physical iPhone, stopping the log collector closes the running app. `stop` also releases this workspace's device leases. It never uninstalls the app or shuts down the phone; hardware has no owned-device registry entry. @@ -293,8 +309,8 @@ app or shuts down the phone; hardware has no owned-device registry entry. ## `device lock` and `device unlock` ```text -stim device lock [id] [--for ] [--wait ] [--json] -stim device unlock [ios|android] [--json] +stim device lock [id] [--slot ] [--for ] [--wait ] [--json] +stim device unlock [ios|android] [--slot ] [--json] ``` Leases a connected physical device to this workspace, so another workspace's @@ -310,7 +326,8 @@ free one in id order. The same rule serves `ios --device` and `android --device` with no id, so two devices on one machine no longer refuse. `unlock` releases every lease this workspace holds, or only the platform -named; releasing nothing is not an error. A `--device` run takes a lease of +named. Adding `--slot ` restricts release to that slot; releasing nothing +is not an error. A `--device` run takes a lease of its own for the length of the run, so `lock` is for holding a device across runs, such as a device-tool session. `stim status` lists every lease on the machine. diff --git a/website/docs/dev-server-and-logs.md b/website/docs/dev-server-and-logs.md index 8f75f854..fcd29a15 100644 --- a/website/docs/dev-server-and-logs.md +++ b/website/docs/dev-server-and-logs.md @@ -6,9 +6,13 @@ description: 'A supervised Metro server and a queryable launch timeline' import StimTabs from '@site/src/components/StimTabs'; +:::note[Command examples] + Commands use `stim`. If it is not installed globally, replace `stim` with `npx stim`. +::: + `stim start` reserves a port for the workspace and starts its React Native or Expo dev server under a detached supervisor. The command exits only after the server answers and Stim verifies its project identity. diff --git a/website/docs/eas-builds.md b/website/docs/eas-builds.md index bb730bb1..54bfd2c2 100644 --- a/website/docs/eas-builds.md +++ b/website/docs/eas-builds.md @@ -6,9 +6,13 @@ description: 'Download a compatible EAS build and run it with Stim' import StimTabs from '@site/src/components/StimTabs'; import PromptBox from '@site/src/components/PromptBox'; +:::note[Command examples] + Commands use `stim`. If it is not installed globally, replace `stim` with `npx stim`. +::: + If your Expo project builds with EAS, Stim can download a matching development build and run it on a simulator, emulator, or connected phone. EAS supplies the native app; Stim manages the workspace's device, Metro port, installation, @@ -17,7 +21,7 @@ loading their own JavaScript from Metro. ## Ask your agent -Replace `ios-simulator` with your project's EAS profile name: +Name the platform and target you want: -{`Use Stim to run this app on an iOS simulator with the EAS profile ios-simulator. Reuse a compatible build. If none matches, show me the EAS build command and ask before starting a cloud build. Check the app logs for errors after launch.`} +{`Run the app on an iOS simulator using an EAS build.`} -The response is illustrative. For Android, ask for an Android emulator and name -its profile. For hardware, ask for your connected iPhone or Android phone and -use a device-compatible profile. +The response is illustrative. Ask for an Android emulator or connected phone to +change the target. With the Stim skill installed, the agent can inspect +`eas.json` and choose a compatible development profile. If none fits or several +remain plausible, it should ask. You can also name a profile for a specific app +variant. New cloud builds still require your authorization. ## Choose a profile diff --git a/website/docs/getting-started.md b/website/docs/getting-started.md index ba468b41..45921f6d 100644 --- a/website/docs/getting-started.md +++ b/website/docs/getting-started.md @@ -80,7 +80,7 @@ com.appandflow.trailhead · ready · cache hit · 58.8s · errors clean`} response={`Trailhead launched on stim-trailhead (iPhone 17 / iOS 26.5). com.appandflow.trailhead · ready · EAS build · errors clean`} > - {`Use Stim to run this app on an iOS simulator with the EAS profile ios-simulator. Reuse a compatible build. If none matches, show me the EAS build command and ask before starting a cloud build. Check the app logs for errors after launch.`} + {`Run the app on an iOS simulator using an EAS build.`} -The EAS prompt assumes an `ios-simulator` profile. Replace it with your -project's profile name; see [EAS development builds](./eas-builds.md) for setup, -Android and device examples, and build-miss behavior. +The agent can choose a compatible EAS profile for the requested target. It +should ask if none fits or the choice is ambiguous. See +[EAS development builds](./eas-builds.md) for setup, Android and device examples, +and build-miss behavior. ## Run work in parallel diff --git a/website/docs/owned-devices.md b/website/docs/owned-devices.md index 28f87909..c3fa8176 100644 --- a/website/docs/owned-devices.md +++ b/website/docs/owned-devices.md @@ -4,9 +4,16 @@ sidebar_position: 3 description: 'Owned devices, physical-device leases, and cleanup' --- +import StimTabs from '@site/src/components/StimTabs'; +import PromptBox from '@site/src/components/PromptBox'; + +:::note[Command examples] + Commands use `stim`. If it is not installed globally, replace `stim` with `npx stim`. +::: + Stim creates and records its local simulators and emulators. Their names start with `stim-`. It never creates, boots, or deletes a simulator or emulator that another tool made. @@ -17,7 +24,77 @@ for the run, then releases the lease. Use `stim device lock` to hold it across runs. Hardware never enters the owned-device registry and is never booted, shut down, or deleted by Stim. -Each workspace keeps its owned-device assignment for later runs. +Each workspace keeps its owned-device assignments for later runs. + +## Multiple devices with slots + +Use `--slot ` to keep multiple targets in one workspace: phone and tablet +simulators, several devices of the same model, Android emulators, and connected +hardware. There is no fixed number of slots; available host resources and any +configured device caps still apply. Omitting the flag uses `default`, including +assignments created before slots were supported. + + +{`Use Stim to test this change on an iPhone simulator, an iPad simulator, and my connected iPhone in this workspace. Use slots named phone, tablet, and hardware. Reuse those slots on later runs. Check the UI and errors on each target, report what you verified, and leave the devices running for me.`} + + +The agent should select installed simulator models and identify the connected +phone before running. A physical iPhone needs a signed development build that +covers its UDID. If several phones are connected, name the one you want. + +### Run and reuse targets + +For example, with the named iPad model installed: + + + +Repeat the same slot and device selectors to reuse an assignment. Choose an +installed model reported by `xcrun simctl list devicetypes`; +replace the iPad model above when needed. Use `--device ` when selecting +among connected iPhones. Android supports the same pattern with +`stim android --slot phone` or `stim android --slot hardware --device `. +Slot names are case-sensitive, 1–64 letters, digits, underscores or hyphens, +and must begin with a letter or digit; prototype-related reserved names are +rejected. A name is scoped to its platform within the workspace. + +Slots share one Metro server and compatible native build caches. Native runs +serialize changes to shared build output; the devices can remain running +together afterward. A shared Metro request cannot prove which slot fetched a +bundle, so Debug launches may report `unverified`. Inspect the intended device +and its logs before claiming success. `reload` remains platform-wide, and named +slots are not supported for remote sessions. Local runs using an +[EAS development build](./eas-builds.md) can use slots. + +### Inspect and stop one slot + + + +The slot filter selects that target's attributed records. Shared Metro logs +need a workspace-wide query. `status` lists the named assignments and leases. +`stop --slot tablet` stops that slot's owned devices and collectors and releases +its leases, while keeping Metro and sibling slots running. The assignment stays +available for another run. Plain `stim stop` handles every slot in the workspace. + +Physical-device leases are separate per slot, but two slots cannot hold the +same physical device at once. `device lock --slot hardware` can retain a lease +across runs; use the platform and device selector shown in the +[command reference](./commands.md#device-lock-and-device-unlock). + +All slots participate in workspace removal and garbage collection. Parked +models share each platform's pool limit: an infrequently reused iPad can be +evicted as the oldest parked simulator when that pool fills. Upgrades preserve +existing ownership state; do not erase it. Use a slot-aware CLI consistently +while named assignments exist, because older versions cannot manage them. ## Local devices diff --git a/website/docs/requirements.md b/website/docs/requirements.md index 082222cf..cccb04df 100644 --- a/website/docs/requirements.md +++ b/website/docs/requirements.md @@ -4,9 +4,13 @@ sidebar_position: 3 description: 'Local and optional remote requirements' --- +:::note[Command examples] + Commands use `stim`. If it is not installed globally, replace `stim` with `npx stim`. +::: + ## All projects - Node 20.19.4 or later on Node 20, or Node 22.12.0 or later. diff --git a/website/docs/settings.md b/website/docs/settings.md index a7f87179..22e3f1d3 100644 --- a/website/docs/settings.md +++ b/website/docs/settings.md @@ -4,9 +4,13 @@ sidebar_position: 2 description: 'Project, repository, machine, and environment settings' --- +:::note[Command examples] + Commands use `stim`. If it is not installed globally, replace `stim` with `npx stim`. +::: + Most projects need no settings. Use `stim guide settings` for descriptions that match the installed version. diff --git a/website/docs/why.md b/website/docs/why.md index ad60e200..fe31e2aa 100644 --- a/website/docs/why.md +++ b/website/docs/why.md @@ -4,9 +4,13 @@ sidebar_position: 1 description: 'Fast, isolated React Native environments for coding agents' --- +:::note[Command examples] + Commands use `stim`. If it is not installed globally, replace `stim` with `npx stim`. +::: + Stim gives each coding agent a complete React Native environment. Each project or git worktree gets a reserved Metro port and an owned simulator or emulator. The agent can build, install, launch, inspect errors, and clean up through one diff --git a/website/docs/worktrees.md b/website/docs/worktrees.md index 704886e0..163636ae 100644 --- a/website/docs/worktrees.md +++ b/website/docs/worktrees.md @@ -6,9 +6,13 @@ description: 'Parallel worktrees that share expensive build caches' import StimTabs from '@site/src/components/StimTabs'; +:::note[Command examples] + Commands use `stim`. If it is not installed globally, replace `stim` with `npx stim`. +::: + ## Create with Git Use Git to choose the branch, path, and starting commit. Prefer a sibling