PhyStack CLI (v7 preview)
Note: v7 is a preview release, published under its own npm tag. Installing it is opt-in and leaves your current CLI untouched until you choose to upgrade. Reference documentation for individual commands is still in progress. Until it is published, the built-in help is the authoritative reference:
phy --help,phy <command> --help, andphy manall include worked examples.
v7 is a new major version of the PhyStack CLI (phy), with a number of improvements over v6.
This page covers what changed, how to install the preview, how to migrate an existing v6 setup, and how to run the CLI in a pipeline.
Key Improvements
Section titled “Key Improvements”- Uniform command structure: Every command follows
phy <resource> <verb>, with the same verbs across resources:list,get,create,update,delete. - Consistent global flags:
-o/--output,--tenant,--dry-run,-y/--yes,--no-input, and--quietbehave identically on every command. - Scriptable output: Tabular output in a terminal, JSON when redirected, and documented exit codes for branching.
- Confirmation and preview on writes: Destructive commands require confirmation,
--dry-runresolves a request without sending it, and settings are validated against the app’s schema before submission. - Keychain-backed credentials: Tokens are held in the operating system keychain where one is available, with a permission-restricted file as the fallback.
- Compiled binary: A single native executable, with no dependency tree to install or maintain.
- Wider command coverage: Media library, analytics, peripherals, device containers and logs, installation settings, and access tokens for automation.
Supported Platforms
Section titled “Supported Platforms”- macOS on Apple Silicon and Intel
- Linux x64 and arm64, including Alpine and other musl distributions
- Windows x64
Installing the Preview
Section titled “Installing the Preview”1. Install the CLI
Section titled “1. Install the CLI”npm i -g @phystack/cli@devThe @dev tag is required. npm i -g @phystack/cli without a tag installs the current stable v6 release, and continues to do so until v7 becomes generally available.
2. Verify the Installation
Section titled “2. Verify the Installation”phy --versionYou should see output similar to:
phy 7.0.0-dev.14 (f597f18e 2026-08-17)target: aarch64-apple-darwinUpgrading
Section titled “Upgrading”Automatic updates are disabled during the preview. Run the install command again to upgrade:
npm i -g @phystack/cli@devReverting to v6
Section titled “Reverting to v6”v7 does not modify v6 configuration. Your existing v6 login and selected tenant remain intact, and nothing needs to be undone before reverting.
Before Your First Run
Section titled “Before Your First Run”Two checks prevent the most common problems when moving from v6.
Clear Legacy Environment Variables
Section titled “Clear Legacy Environment Variables”v7 reads a new set of PHY_* environment variables and ignores the older PHYSTACK_* and PHYGRID_* variables without warning. A legacy variable left in your shell profile will appear to have no effect on the CLI. List anything still set:
env | grep -E 'PHY_|PHYSTACK_|PHYGRID_'The variables you are most likely to be carrying over:
| Legacy variable | v7 replacement |
|---|---|
PHYSTACK_DEVELOPER_TOKEN | PHY_TOKEN |
PHYSTACK_TENANT_ID | PHY_TENANT |
PHYSTACK_REGISTRY_PUSH_USERNAME / PHYSTACK_REGISTRY_PUSH_PASSWORD | PHY_REGISTRY_PUSH_USERNAME / PHY_REGISTRY_PUSH_PASSWORD |
PHYSTACK_REGISTRY_PULL_USERNAME / PHYSTACK_REGISTRY_PULL_PASSWORD | PHY_REGISTRY_PULL_USERNAME / PHY_REGISTRY_PULL_PASSWORD |
Any other variable beginning with PHYSTACK_ or PHYGRID_ is no longer read.
Remove Conflicting Installations
Section titled “Remove Conflicting Installations”The retired @phygrid/cli package also installs a command named phy. When both packages are present, the active command depends on the order they were installed. Remove the old package:
npm uninstall -g @phygrid/clihash -rwhich -a phywhich -a phy should return a single path.
First Run
Section titled “First Run”1. Authenticate
Section titled “1. Authenticate”phy loginThe command prints a one-time code, opens the approval page in your browser, and completes once you approve. Confirm that the code shown in your terminal matches the code in the browser before approving. Your credential is never printed.
Note: You need to log in again even if you were already authenticated with v6, because v7 stores credentials in a different location. Tokens already in use in scripts are unaffected.
Headless Authentication
Section titled “Headless Authentication”On a remote or headless machine, print the verification URL and code to complete authentication on another device:
phy login --no-browser2. Select a Tenant
Section titled “2. Select a Tenant”phy whoamiphy tenant listphy tenant set <your-tenant-slug>The tenant you set becomes the default for subsequent commands.
3. Verify Your Setup
Section titled “3. Verify Your Setup”phy device listIf your devices are listed without errors, the CLI is configured correctly.
Signing Out
Section titled “Signing Out”phy logoutThis removes the local credential and revokes the session.
Configuration and Credential Storage
Section titled “Configuration and Credential Storage”| v6 | v7 | |
|---|---|---|
| Configuration | Multiple files in ~/.config/phystack-cli/ | A single file, ~/.config/phy/config.toml |
| Credential at rest | Plain text file | The operating system keychain (macOS Keychain, Windows Credential Manager, or the Linux Secret Service), falling back to a 0600 file where no keychain is available |
The two locations are independent. v7 never reads, writes, or deletes v6 configuration, and v6 has no knowledge of v7 configuration. Either version can be installed over the other without affecting the other’s state, and switching back leaves you logged in where you were.
Inspecting Your Configuration
Section titled “Inspecting Your Configuration”phy config viewSecrets are redacted in this output, which makes it safe to attach to a support request.
Resetting v7
Section titled “Resetting v7”phy logoutrm -rf ~/.config/phyTip: Use
phy logoutrather than deleting keychain entries manually. It clears both the keychain entry and the configuration file on every platform.
Contexts
Section titled “Contexts”A context pairs a login with a default tenant. One context is created for you the first time you log in, which is all most users need. Additional contexts are useful when you work as more than one user, or when you want to switch between default tenants.
phy config get-contexts # List contexts, the active one is markedphy config current-context # Print the name of the active contextphy config use-context <name> # Switch the active contextTwo behaviors to be aware of:
set-contextsaves a context without switching to it. When the active context is unchanged, the command reports this and prints theuse-contextcommand to run.set-contextmodifies only the fields you pass. All other fields on an existing context are preserved. Pass--replaceto reset a context completely.
To override the tenant for a single command, pass --tenant <id-or-slug>.
Command Changes From v6
Section titled “Command Changes From v6”The complete command list is available through phy --help. The following commands were renamed:
| v6 | v7 |
|---|---|
phy dev list | phy device list |
phy dev shell <device> | phy device shell <device> |
phy dev vnc / forward / screen-devtools / cp | phy device vnc / forward / screen-devtools / cp |
phy tenant select <slug> | phy tenant set <slug-or-id> |
phy app build (building a bundle locally) | phy app package |
phy app publish | phy app build create, with --publish to do both in one step |
phy inst list | phy installation list, and phy inst remains as an alias |
phy login --use-device-code | phy login --no-browser |
phy login --use-developer-token <token> | Set PHY_TOKEN, or use phy auth set-token |
phy update | Run npm i -g @phystack/cli@dev again |
Devices can be identified by id or name in every command, and the verb always precedes the target:
phy device shell my-device # Correctphy device my-device shell # IncorrectOutput Formats and Exit Codes
Section titled “Output Formats and Exit Codes”Output adapts to its destination. Commands print a table in a terminal and JSON when the output is piped or redirected, which means the following already produces JSON:
phy device list | jq '.[].name'To request a specific format, pass -o:
| Format | Use |
|---|---|
table | Default in a terminal |
json | Default when piped or redirected |
yaml | Configuration-style output |
wide | Additional columns |
name | Ids or names only, one per line |
Exit codes are documented and stable. Scripts should branch on the exit code rather than parse command output:
| Code | Meaning |
|---|---|
0 | Success |
2 | Validation error or bad request |
3 | Authentication or permission error |
4 | Not found |
5 | Conflict |
6 | Server error |
7 | Partially applied, for bulk operations |
phy device exec returns the exit code of the remote command, in the same way as ssh. A command that fails on the device is therefore visible to your script.
Lists are paginated with a default page size of 50. Use --page, --page-size, --sort, and --all to control the result set. In a terminal, long tables page as you read them.
Automation and CI
Section titled “Automation and CI”The CLI is intended to run unattended. When it is not attached to a terminal, it defaults to non-interactive behavior: JSON output, no spinners, and no prompts. --no-input forces this behavior in any context, and it is applied automatically when CI is set.
A pipeline requires no phy login and no on-disk configuration. Credentials and scope are supplied entirely through environment variables.
1. Create an Access Token
Section titled “1. Create an Access Token”Do not run phy login in a pipeline. Create a token once from your own machine:
phy token create ci-pipeline # The secret is displayed oncephy token list # Names and expiry only, never the secretphy token delete <id> # RevokeStore the secret in your CI provider’s secret storage. PHY_TOKEN takes precedence over every other credential source, and works on a machine that has never logged in. Tokens already in use with v6 remain valid.
2. Set the Token and Tenant
Section titled “2. Set the Token and Tenant”env: PHY_TOKEN: ${{ secrets.PHY_TOKEN }} PHY_TENANT: <tenant-id>Important:
PHY_TENANT, or an explicit--tenanton each command, is required in CI. Commands that modify data refuse to run unattended against a tenant inherited from saved configuration. This prevents an automated job from writing to whichever tenant happened to be selected.
Screen and Web Apps
Section titled “Screen and Web Apps”Screen and web apps require no credentials beyond PHY_TOKEN and PHY_TENANT. The front-end bundle is packaged into the .gridapp archive that the CLI produces, and there is no container image to push.
Build your project, then submit and publish in one step:
- run: npm ci- run: npm run build- run: phy app build create my-screen-app --dir . --publish--dir packages the source for you and --publish waits for processing to finish before publishing the build. The version is derived automatically as the next minor version after the app’s latest build. --push and --image do not apply to these app types and are rejected.
Edge Apps
Section titled “Edge Apps”Edge apps are distributed as container images. A pipeline that builds one needs Docker available and two registry credentials, supplied through the environment rather than through the interactive phy registry login:
| Variable | Purpose |
|---|---|
PHY_REGISTRY_PUSH_USERNAMEPHY_REGISTRY_PUSH_PASSWORD | Pushes the image built on the runner |
PHY_REGISTRY_PULL_USERNAMEPHY_REGISTRY_PULL_PASSWORD | Attached to the build and used by devices to retrieve the image |
These variables take precedence over any credential stored locally by phy registry login.
Important: The pull credential must be read-only. It is attached to the build and distributed to devices, and a write-capable token is rejected. Create two separate tokens in your registry: one read-only for pulling, and one with write access for pushing.
A complete edge app job:
- uses: docker/setup-buildx-action@v3
- run: phy app build create my-edge-app --dir . --push --publish env: PHY_TOKEN: ${{ secrets.PHY_TOKEN }} PHY_TENANT: ${{ vars.PHY_TENANT }} PHY_REGISTRY_PUSH_USERNAME: ${{ secrets.REGISTRY_PUSH_USERNAME }} PHY_REGISTRY_PUSH_PASSWORD: ${{ secrets.REGISTRY_PUSH_PASSWORD }} PHY_REGISTRY_PULL_USERNAME: ${{ secrets.REGISTRY_PULL_USERNAME }} PHY_REGISTRY_PULL_PASSWORD: ${{ secrets.REGISTRY_PULL_PASSWORD }}Additional details for the edge path:
--pushbuilds a multi-architecture image forlinux/arm64/v8andlinux/amd64withdocker buildx, and pushes it before the build is submitted. The CLI creates the buildx builder it needs if one is not already present.- The push credential is seeded into a temporary Docker configuration for the duration of that command. There is no
docker loginstep, and the credential never reaches the platform or a device. --imageis optional. When it is omitted alongside--push, the image reference is derived as<registry-host>/<namespace>/<app>:<version>. Pass it explicitly to publish to a different repository.- Without
--push, the image must already exist in the registry. The CLI verifies the tag before submitting the build. - When no pull credential is configured, the build fails with a message naming these variables rather than publishing an image that devices cannot retrieve. For a public image that requires no credential, pass
--no-registry-credentialinstead. - Use
--build-context <dir>when your Dockerfile is not in the working directory.
Reading Results in a Pipeline
Section titled “Reading Results in a Pipeline”Every command emits JSON when its output is redirected, and exit codes are stable, which lets a script branch without parsing prose:
phy device list -o json > devices.jsonphy app build list my-edge-app -o json | jq -r '.items[0].version'See Output Formats and Exit Codes for the full list.
Safety Behavior
Section titled “Safety Behavior”- Destructive commands such as
deleteandrebootrequire confirmation.-yskips the prompt, and is mandatory for those commands when they are not run from a terminal. --dry-runprints the change that would be sent and sends nothing. Read-only lookups, such as resolving a device name, still run.- Commands that modify data refuse to run in a script when the tenant was inherited from the active context rather than passed explicitly with
--tenant. - Settings writes are validated against the app’s schema on your machine. An invalid value fails immediately with a readable message instead of a server error.
Container Registry Credentials for Edge Apps
Section titled “Container Registry Credentials for Edge Apps”Edge apps require two distinct registry credentials, managed with the same commands you would expect from docker login:
phy registry login docker.io # Prompts for a read-only pull credential and a push credentialphy registry status # Shows what is configured, never the secretsphy registry logout docker.io- Pull credential: Must be read-only. It is attached to the build and used by devices to retrieve the image, and a write-capable token is rejected.
- Push credential: Used locally to push the image. It is never sent to the platform or to a device.
Both are stored in your keychain, and no data leaves your machine when you run phy registry login.
phy registry login is the interactive path for a workstation. In a pipeline, supply both credentials through environment variables as described in Edge Apps.
Important: If your app’s
package.jsonstill contains an embeddeddocker-credentialsblock, or pins an old CLI as a dependency,phy app packagestops and reports what to remove. The CLI is a global tool in v7 and is never pinned inside a project.
New Commands in v7
Section titled “New Commands in v7”The following commands have no v6 equivalent:
phy media: Media library operations, includingls,tree,mkdir,mv,rm,upload,download, andsearchphy analytics: Reports over your data, includingschema,query,rank, andraw-eventsphy peripheralandphy descriptor: Read peripheral state, change operator-writable settings, invoke actions, and browse or publish descriptorsphy token: Access tokens for automationphy registry: Pull and push registry credentialsphy config: Context managementphy device logs,exec,reboot, andcontainer list|logs|stats|restart|stop|execphy installation settings get|set|clear: Installation settings with device-level overrides and a--resolvedview, alongsideactivate,deactivate,clone, anddevice add|remove|listphy space,user,role,invitation,content-tag,short-url,cloud-instancephy openapi: The live API specificationphy completions <shell>andphy man: Shell completion and a manual pagephy whoamiandphy auth status: Confirm your identity and which credential is in use
Platform Notes
Section titled “Platform Notes”The CLI behaves consistently across platforms. The following details are specific to individual environments.
Remote Device Access Requires an SSH Client
Section titled “Remote Device Access Requires an SSH Client”phy device shell, exec, cp, logs, forward, vnc, and screen-devtools operate over an SSH tunnel and use the ssh client installed on your machine. macOS and Windows 10/11 include one. On a minimal Linux installation or inside a container, install your distribution’s openssh-client package first.
Linux: Credential Storage Depends on the Session
Section titled “Linux: Credential Storage Depends on the Session”On a desktop with a running keyring service such as GNOME Keyring or KWallet, your credential is stored there. On a headless or SSH session with no keyring available, and on the Alpine and musl builds, the CLI stores it in ~/.config/phy/config.toml with 0600 permissions and reports that it has done so. Both are supported. Where the file is used, treat it as a secret.
Linux and Headless: Authentication Without a Browser
Section titled “Linux and Headless: Authentication Without a Browser”phy login only attempts to open a browser when a graphical session is present. Otherwise it prints the verification URL and code for you to complete elsewhere. Pass phy login --no-browser to force this behavior.
Linux: VNC Viewer Launch
Section titled “Linux: VNC Viewer Launch”Most Linux desktops have no handler registered for vnc:// addresses. On those systems phy device vnc forwards the port and prints the address for you to open in your viewer. Pass --no-open to skip the launch attempt entirely.
Tools Outside the CLI
Section titled “Tools Outside the CLI”v7 is the platform command line. Capabilities that v6 bundled but that work better as dedicated tools have been separated out, which keeps the CLI focused and allows each tool to release on its own schedule.
- Device simulator: Shipped as its own package,
@phystack/device-simulator, installed and versioned separately. The command isphy-simulator, and it replacesphy simulatorfrom v6. See the Simulator reference. - PhyOS image flashing: Becoming a standalone tool in a future release, replacing
phy flashfrom v6.
Commands That Remain in v6
Section titled “Commands That Remain in v6”A number of v6 commands fall outside the scope of v7 and are still available in v6:
- Local PhyOS virtual machines,
phy vm - Management of legacy IoT-Edge devices,
phy legacydev, because v7 device commands target PhyOS devices - Local developer-mode runs against a device,
phy dev developandphy app deploy - Screen app emulation device selection,
phy dev select - Importing an HTML project as a bundle,
phy app import - Uploading an app description,
phy app upload-description, where v7 usesphy app update --setinstead
If your work depends on any of these, continue to use v6 for that task. Switching between the two versions is a single install command in either direction, as described in Reverting to v6.
Getting Help
Section titled “Getting Help”phy # Overview and common commandsphy --help # All command groupsphy <command> --help # Verbs, flags, and worked examplesphy man # Manual pageThis is a preview release, and reports of problems during the preview are valuable. When reporting an issue, include the exact command you ran, what you expected, what happened, and the output of phy --version. Adding -v to the failing command provides request-level detail that is usually enough to identify the cause.
For additional help, contact support at [email protected].