Skip to content
LogoLogo

CLI

picked is the command-line tool for local Picked development. It generates TypeScript types from your workspace schema and lets you switch which project or workspace your local tooling loads — without hand-editing picked.config.ts. It also copies the content of a workspace from one project to a different project.

Installation

The picked package holds this command, the client, and the picked.config helpers:

npm install picked

The command reads picked.config.ts from the current directory, so run it from your project root. See How to authenticate the CLI to sign in.

@picked/cli holds the command on its own, for a project that wants no other part of the package.

Commands

CommandDescription
picked loginSign in with your browser (OAuth) to the API origin of the current directory. Stores a session under ~/.picked/auth/.
picked logoutClear the stored session for the current directory's API origin.
picked whoamiPrint the identity signed in to the API origin of the current directory.
picked statusPrint the resolved selection and the committed picked.config default.
picked workspace listList each org, project, and workspace that you can read. Alias ls. --json gives machine output.
picked workspace useSet the active project or workspace. Alias picked use. Interactive, or --project and --workspace.
picked workspace exportWrite a workspace, or the published version of a project, to a bundle directory.
picked workspace importCreate a new draft workspace in a project from a bundle directory. --publish also publishes it.
picked generate typesRead the workspace schema and write picked-env.d.ts. --check verifies and writes nothing.

picked generate types

Writes the typed schema declaration. See Type generation for the picked.config.ts reference and the generated output.

picked generate types

In CI, --check writes nothing and fails when the committed types are stale:

picked generate types --check
# → "Types are up to date (`…/src/picked-env.d.ts`)."  (status 0)
# → "Types are out of date: `…/src/picked-env.d.ts`"   (status 1)

picked workspace list

picked workspace list
Acme Corp. (acme-corporation)
  Storefront [proj_a1b2]
    Default Storefront [LIVE] (live)
    Checkout rework [DRAFT]

--json gives a machine-readable tree. Each prompt and heading goes to stderr, so the stdout of --json stays clean when you send it to another command.

picked workspace use

Sets the active selection, then regenerates types. See How to switch workspaces for the full set of steps.

picked workspace use                                  # interactive picker
picked workspace use --project proj_a1b2              # the project's published (live) version
picked workspace use --project proj_a1b2 --workspace ws_id      # preview a specific workspace via its token
Active workspace: Checkout rework [DRAFT] in project proj_a1b2 (source: preview)
Generated types at /app/src/picked-env.d.ts

--no-generate sets the selection and leaves the types as they are.

picked workspace export

Writes one workspace of a project to a bundle directory. The bundle holds every part of the workspace: features, steps, fields, actions, conditions, experiences, workflows, page layouts, sections, and content entries. It also holds a copy of each asset that the content entries use.

picked workspace export --project proj_a1b2 --live --out ./bundle
picked workspace export --project proj_a1b2 --workspace ws_id --out ./bundle
Exported workspace "Snapshot of Default Storefront" with 12 assets to /app/bundle
FlagDescription
--project <id>The project that holds the workspace. Required.
--liveWrite the version that the project serves now. The bundle does not include draft changes that you made after you published that version.
--workspace <id>Write this workspace, with its draft changes. The command stops with status 1 when you use --live and --workspace together.
--out <dir>The bundle directory. It must be in the current directory, and be empty or not exist. Required.

The command stops with status 1 when:

  • --live is used and the project has no published version.
  • The workspace is not in --project.
  • The API rejects the request. The message shows the error code and one line for each problem.
  • The size of a downloaded asset, or its sha256 hash, is different from the value in the bundle manifest.

The error code UNRESOLVED_REFERENCE shows that a part of the workspace refers to a part that the workspace does not have. For example, a content entry uses a deleted section, a flow goes to a deleted experience, or a workflow starts from a deleted action. Each line names the part, its key or name if it has one, the location of the reference in the part, and the missing id:

Export of workspace ws_id failed:
  UNRESOLVED_REFERENCE: Cannot export experience 'exp_1' (key 'home'): flow node references experience 'exp_gone', which does not belong to the workspace, at flow_json.nodes.1.targetExperienceId (workspaceId)

Remove or change each reference, then run the command again.

The credential needs the organization_workspace/read scope on the project. With --live, it also needs the organization_projects/read scope.

Bundle directory

PathContents
bundle.jsonThe workspace. formatVersion is 1. assets lists each asset version with its fileName, mimeType, sizeBytes, and sha256 hash.
assets/<sha256>The bytes of one asset. The file name is the sha256 hash of the bytes, in lowercase.

The command writes the bundle into a temporary directory next to --out, and writes bundle.json last. When the bundle is complete, the command moves it to --out. When the command fails, it removes the temporary directory, and you can run the same command again.

Each request body and response body of the Picked API can be at most 4.5 MB. For a very large workspace, picked workspace export and picked workspace import fail when its bundle.json is larger than this limit. Asset files do not count, because the command downloads and uploads them directly.

picked workspace import

Creates a new draft workspace in a project from a bundle directory, then prints the id of the new workspace. The command does not change the other workspaces of the project. It changes the published version only when you use --publish.

picked workspace import --project proj_c3d4 --in ./bundle --name "Copy of storefront" --publish
Imported workspace "Copy of storefront" as ws_new into project proj_c3d4 (assets: 12 uploaded, 0 already in the project).
Published workspace ws_new.
FlagDescription
--project <id>The project to import into. It can be in a different organization or a different API deployment. Required.
--in <dir>The bundle directory that picked workspace export wrote. It must be in the current directory. Required.
--name <name>The name of the new workspace. The default is the workspace name in the bundle.
--publishPublish the new workspace after the command creates it.

The command sends the sha256 hash of each asset to the API before it uploads the asset. When the project already has an asset with the same bytes, the new workspace uses that asset. The command does not upload the bytes again. When you import the same bundle into the same project two times, the second command uploads no assets. Each command creates a new workspace.

Every part of the workspace gets a new id in the target project. The key of an experience does not change. The nodes of a workflow keep their ids, and a workflow that starts from an action starts from the new copy of that action.

The API calculates the scopes of each workflow from the tools that the workflow uses. For each tool scope that a workflow does not get by default, the credential must have that scope. If it does not, the API rejects the bundle with the error code WORKFLOW_SCOPES_NOT_HELD, and the message names the workflow, the tool and the scope.

The command stops with status 1 when:

  • An asset file does not exist, or its size or sha256 hash is different from the bundle manifest. The command makes no API request in this case.
  • An asset upload fails.
  • The API rejects the bundle. The message shows the error code, for example UNSUPPORTED_FORMAT_VERSION, UNRESOLVED_REFERENCE or WORKFLOW_SCOPES_NOT_HELD.
  • The API rejects the import request with a GraphQL error, for example because the credential does not have the necessary scopes.
  • The import request fails on the API with a different GraphQL error, for example INFRASTRUCTURE_ERROR.
  • The import request gets no GraphQL answer from the API, for example because of a network failure, a timeout or an HTTP error. The import request has a longer timeout than the other requests.
  • --publish is used and the API does not publish the workspace. The message shows the id of the new draft workspace.

When the API rejects the import request, the GraphQL error code is FORBIDDEN, UNAUTHENTICATED, BAD_USER_INPUT or GRAPHQL_VALIDATION_FAILED. When an asset upload fails or the API rejects the bundle or the import request, the API does not create a workspace. The command deletes the assets that it uploaded, and the message names them. Assets that were already in the project stay.

When the import request fails with a different GraphQL error or gets no GraphQL answer, the new workspace can exist in the project. The command keeps the assets that it uploaded, and the message names them. When the project has no new workspace, no workspace uses these assets.

The credential needs the organization_projects/read, organization_projects/update and organization_workspace/update scopes on the project. For a bundle with workflows, it also needs the scopes of their tools, as described above.

Authentication

picked login signs in through the browser. It uses an authorization-code flow with PKCE against the Picked OAuth server. picked whoami prints the identity for the current origin. picked logout clears it.

The CLI holds one auth config file for each API origin, outside each repository. Every command reads and writes only the origin that the current directory resolves to, and never a session for another API.

FileContents
~/.picked/auth/<origin>.jsonThe OAuth session for one API origin — access token, refresh token, expiry — with the CLI's registered client id for that origin. File mode 600. Refreshed as it nears expiry.

An API deployment with no OAuth client registration rejects picked login, and has no other flow.

A CLI session is a developer credential. It is not dashboard sign-in.

API key

When PICKED_API_KEY is set, each command that calls the API sends the key in the X-API-Key header. The CLI does not read the stored session. An API key lets a run that has no browser, for example a CI job, call the API. An API key for one project can read and write only that project.

An API key does not identify a user. When PICKED_API_KEY is set, picked login, picked whoami, and picked workspace list stop with status 1.

Environment variables

VariableEffect
PICKED_API_URLThe API origin that the CLI reads. Supersedes picked.config apiUrl and the https://api.picked.app default.
PICKED_API_KEYAn API key. When set, the CLI sends it as X-API-Key in place of the stored session.
PICKED_PROJECT_IDSupersedes the resolved project id, above the active selection and the committed configuration.
PICKED_PREVIEW_TOKENSupersedes the preview token. Applies only when the resolved source is preview.

How the selection resolves

Tooling — picked generate types and the Vite plugin — resolves the configuration in this order. Each layer supersedes the layer before it:

  1. picked.config.ts — the committed default: projectId, source, and previewToken.
  2. .picked/settings.json — the per-developer active selection that picked workspace use writes. It supersedes projectId and source, and Git ignores it.
  3. Environment variables — PICKED_PROJECT_ID and PICKED_PREVIEW_TOKEN supersede both, for a CI or headless run.

picked status prints the resolved result.