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 pickedThe 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
| Command | Description |
|---|---|
picked login | Sign in with your browser (OAuth) to the API origin of the current directory. Stores a session under ~/.picked/auth/. |
picked logout | Clear the stored session for the current directory's API origin. |
picked whoami | Print the identity signed in to the API origin of the current directory. |
picked status | Print the resolved selection and the committed picked.config default. |
picked workspace list | List each org, project, and workspace that you can read. Alias ls. --json gives machine output. |
picked workspace use | Set the active project or workspace. Alias picked use. Interactive, or --project and --workspace. |
picked workspace export | Write a workspace, or the published version of a project, to a bundle directory. |
picked workspace import | Create a new draft workspace in a project from a bundle directory. --publish also publishes it. |
picked generate types | Read 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 typesIn 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 listAcme 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 tokenActive 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 ./bundleExported workspace "Snapshot of Default Storefront" with 12 assets to /app/bundle
| Flag | Description |
|---|---|
--project <id> | The project that holds the workspace. Required. |
--live | Write 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:
--liveis 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
sha256hash, 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
| Path | Contents |
|---|---|
bundle.json | The 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" --publishImported workspace "Copy of storefront" as ws_new into project proj_c3d4 (assets: 12 uploaded, 0 already in the project).
Published workspace ws_new.
| Flag | Description |
|---|---|
--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. |
--publish | Publish 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
sha256hash 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_REFERENCEorWORKFLOW_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.
--publishis 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.
| File | Contents |
|---|---|
~/.picked/auth/<origin>.json | The 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
| Variable | Effect |
|---|---|
PICKED_API_URL | The API origin that the CLI reads. Supersedes picked.config apiUrl and the https://api.picked.app default. |
PICKED_API_KEY | An API key. When set, the CLI sends it as X-API-Key in place of the stored session. |
PICKED_PROJECT_ID | Supersedes the resolved project id, above the active selection and the committed configuration. |
PICKED_PREVIEW_TOKEN | Supersedes 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:
picked.config.ts— the committed default:projectId,source, andpreviewToken..picked/settings.json— the per-developer active selection thatpicked workspace usewrites. It supersedesprojectIdandsource, and Git ignores it.- Environment variables —
PICKED_PROJECT_IDandPICKED_PREVIEW_TOKENsupersede both, for a CI or headless run.
picked status prints the resolved result.
Related
- How to authenticate the CLI — install and sign in.
- How to switch workspaces — the draft-preview workflow.
- Type generation —
picked.config.tsand the generated types. - Vite plugin — reads the same selection in development and in a build.
- Preview, cache, and crawlers — how a preview token behaves.
