Simulator
Note: The simulator supports both Node and Python edge apps, as well as Node-based screen apps. Any project scaffolded with
phy app createis ready to run against the simulator out of the box.
The PhyStack CLI includes a local device simulator that simulates the on-device environment and runtime locally, letting you test application logic, settings behavior, and more. You can also test messaging between multiple apps running on your computer and connected to the same simulator instance. The simulator runs in offline mode and does not fully replicate the real device environment, so always verify your app on a real device before publishing.
Screen and edge boilerplate templates already integrate with the simulator out of the box.
Project Structure Requirements
The simulator expects your project to follow a specific structure. Projects scaffolded with phy app create meet these requirements automatically.
Required for all apps
package.jsonat the project root with:"application-type": must be"screen"or"edge"(used for auto-detection). You can also pass--typeto override this."name": used to identify the app in the simulator
Screen apps
- A
"start"script inpackage.json(e.g.,"start": "vite"), this is used as the launch command - Settings in
src/settings/index.json(optional, defaults are generated fromschema.tsif the file doesn’t exist)
Edge apps
- With Dockerfile (recommended): a
Dockerfileat the project root. The simulator builds the image and runs the container with environment variables injected. Container configuration is read fromsettings.jsonat the project root. - Without Dockerfile: falls back to the
"start"script inpackage.json, similar to screen apps - Settings in
src/settings/index.json(optional, same behavior as screen apps)
If
package.jsonis missing, the simulator exits with an error. Ifapplication-typeis missing and--typeis not passed, it will fail with “Cannot detect app type.”
Starting the Simulator
The simulator is a standalone server that runs in the background. Start it in a separate terminal before running any apps:
phy simulator start
This can be run from any directory, the simulator listens on port 55000 and serves all apps launched against it.
| Option | Description | Default |
|---|---|---|
-p, --port <port> | Port to listen on | 55000 |
Running Apps
Once the simulator is running, launch an app against it:
phy simulator run <path>
To run the app in the current directory:
phy simulator run .
| Option | Description | Default |
|---|---|---|
--type <type> | Override app type (screen or edge) | Auto-detected from application-type in package.json |
--dev-command <command> | Override launch command | npm start |
--settings-dir <path> | Path to the directory containing index.json with local settings | src/settings |
How It Works
The simulator injects the PHYSTACK_SIMULATOR_URL environment variable, which instructs the PhyStack SDK in your app to connect to the local simulator instance instead of the edge runtime on the device. It also creates a local simulated twin and provides the mandatory TWIN_ID environment variable so your app can connect when running locally.
For screen apps, the TWIN_ID must be passed to the browser as a URL hash parameter (/#instanceId=<twin-id>). This mirrors how the production screen bootloader delivers the instance ID to screen apps running inside iframes. The Vite config in the screen app boilerplate handles this automatically by opening the browser with the correct hash when the simulator is active.
For this reason, your launch script should ensure these environment variables are propagated to your app on start. Screen and edge app boilerplate created using the CLI configures this for you out of the box.
When you run phy simulator run, the CLI performs the following steps:
- App type detection, reads
application-typefrompackage.json, or uses the--typeflag if provided - Twin and settings setup, creates a virtual simulated twin identity for the app and uses your local settings from
src/settings/index.json(generates defaults fromschema.tsif the file doesn’t exist) - Launch:
- Screen apps runs
npm start(or your custom--dev-command) - Edge apps with Dockerfile builds a Docker image and runs the container with Docker config from
settings.json - Edge apps without Dockerfile falls back to
npm start(or your custom--dev-command)
Troubleshooting
“No package.json found”
The simulator requires a package.json at the project root with "application-type": "edge" (or "screen"), this is how it identifies and launches the app, regardless of the runtime inside. Both Node and Python edge templates scaffold this file alongside their Dockerfile. You’ll see this error if you ran phy simulator run from a directory without a package.json or pointed it at the wrong path. Make sure you run it from your project root.
“Cannot detect app type”
Your package.json is missing the "application-type" field. Add "application-type": "screen" or "application-type": "edge", or pass --type screen / --type edge.
“Simulator is not running”
Start the simulator first with phy simulator start in a separate terminal. The simulator server must be running before you can launch apps against it.
“No Dockerfile or start script found”
Your edge app has no Dockerfile at the project root and no "start" script in package.json. Add one or the other. For Docker-based edge apps, the Dockerfile should be at the project root (not in a subdirectory).
Settings not loading
The simulator looks for settings in src/settings/index.json by default. If your settings are elsewhere, pass --settings-dir <path>. The JSON file must contain settings nested under app.gridApp.settings.