pixi-pfx CLIDrive prefix.dev from the command line. pixi-pfx wraps the GraphQL API as a pixi plugin, with tables for humans and a JSON envelope for scripts and agents.
pixi-pfx is a command-line client for the prefix.dev GraphQL API. It ships as a pixi plugin, so once installed it is available both as pixi-pfx and as pixi pfx. You can manage channels, packages and API keys from a terminal or from CI, and every command can emit a machine-readable JSON envelope.
Source and issue tracker
pixi-pfx is open source at github.com/prefix-dev/pixi-pfx. Please file bug reports and feature requests there. The release binaries are built in that repository as well.
The client is written in Rust and checks every query against the prefix.dev schema at compile time with cynic, so a renamed or removed field breaks the build rather than failing at runtime.
Install
pixi-pfx is packaged on conda-forge for linux-64, linux-aarch64, osx-64, osx-arm64 and win-64. Install it as a global tool:
pixi global install pixi-pfxEvery push to main also publishes a development build to the pixi-extensions channel on beta.prefix.dev, if you want the latest changes before they are released:
pixi global install -c https://beta.prefix.dev/pixi-extensions pixi-pfxTo build from source instead:
# from git
pixi global install --git https://github.com/prefix-dev/pixi-pfx.git
# from a local checkout
pixi global install --path .
# plain cargo, the binary lands in target/release/pixi-pfx
cargo build --releaseAuthenticate
pixi-pfx reads rattler's authentication storage, the same credentials that pixi auth login and rattler auth login write. If you are already logged in to prefix.dev there is nothing to set up. OAuth access tokens are refreshed automatically:
$ pixi-pfx auth whoami
Logged in as: wolfvTo use a specific API key instead, for example in CI, pass --token or set PREFIX_DEV_API_TOKEN. An explicit token always takes precedence over stored credentials:
export PREFIX_DEV_API_TOKEN=<TOKEN>
pixi-pfx auth whoami
# equivalent
pixi-pfx --token <TOKEN> auth whoamiRead-only queries against public channels need no credentials. To see which credential source would be used without printing any secret, run pixi-pfx auth status. See API and API keys for how tokens work, or create one with the CLI as shown below.
Output: tables or JSON
By default commands print a key/value block for a single object and a table for a list. Long cells are truncated to keep the table narrow, and paginated commands print a Page x/y (n total) footer.
$ pixi-pfx package search numpy --limit 3
NAME CHANNEL VERSION PLATFORMS SUMMARY
numpy conda-forge 2.5.2 linux-64, linux-aarch64, linu… The fundamental package for scientific …
numpy emscripten-forge-dev 2.4.4 emscripten-wasm32 The fundamental package for scientific …
numpy emscripten-forge-3x 2.4.4 emscripten-wasm32 The fundamental package for scientific …
Page 1/1 (3 total)Add --json for a stable JSON envelope that scripts and agents can consume. Field names inside data are snake_case, and details is only present for GraphQL errors.
{"ok": true, "data": { "...": "..." }}
{"ok": false, "error": {"code": "GRAPHQL_ERROR", "message": "...", "details": {}}}Successful commands exit 0 and failures exit 1; in table mode the error goes to stderr as error [CODE]: message. The error codes are stable strings:
HTTP_ERROR: the request to the endpoint failed.GRAPHQL_ERROR: the API returned GraphQL errors, or the response could not be decoded.AUTH_STORAGE_ERROR: rattler's credential storage could not be opened or refreshed.INVALID_ARGUMENT: an argument was malformed, for example invalid JSON in--entries.JSON_ERROR: serializing or deserializing JSON failed.
Global options
These three options are global and can appear anywhere on the command line:
--json: emit the JSON envelope instead of tables.--token <TOKEN>: API token to authenticate with. Also read fromPREFIX_DEV_API_TOKEN. Defaults to rattler's auth storage.--endpoint <URL>: GraphQL endpoint,https://prefix.dev/api/graphqlby default. Point it athttps://beta.prefix.dev/api/graphqlto use beta.
Channels
Find and inspect
# details for one channel (public channels need no auth)
pixi-pfx channel get conda-forge
# list channels
pixi-pfx channel list --limit 10
pixi-pfx channel list --owner myuser --order-by size --direction desc
pixi-pfx channel list --search conda --limit 5channel list is paginated with --limit (default 25) and --page (0-indexed). --order-by accepts name, size, created-at, package-count, namespace and billing-owner, combined with --direction asc|desc. Note that --search orders results by name similarity rather than filtering them, so the reported total stays the same.
Create, update, delete
pixi-pfx channel create my-channel --description "My channel" --public
pixi-pfx channel update my-channel --description "Updated" --public false
pixi-pfx channel delete my-channelOn create, --public is a flag; on update it takes an explicit true/false, so visibility can be turned off again. Both commands also accept --logo <URL>, the CEP-0042 relations --relation-base and --relation-overrides, and --allow-v3-uploads true|false for packages that need v3 repodata. The same settings are described in Create and configure a channel.
Members and trusted publishers
# roles: owner, contributor, viewer
pixi-pfx channel add-member my-channel someuser contributor
pixi-pfx channel remove-member my-channel someuser
# OIDC publishers, for keyless uploads from CI
pixi-pfx channel add-github-oidc my-channel --owner org --repo repo --workflow build.yml
pixi-pfx channel add-gitlab-oidc my-channel --namespace group --project proj --workflow .gitlab-ci.yml
pixi-pfx channel add-google-oidc my-channel --email sa@project.iam.gserviceaccount.com
pixi-pfx channel delete-oidc my-channel <publisher-id>
# hand the channel to someone else
pixi-pfx channel transfer my-channel new-ownerThe GitHub and GitLab publishers take an optional --environment; the Google publisher takes an optional --sub constraint. All three accept --access-mode (all, read, read-write or read-write-delete), and channel get lists publishers with their ids and access modes. See Publish packages and Manage channel access.
Notices
CEP-6 notices are shown on the channel page and served to compatible conda clients:
pixi-pfx channel add-notice my-channel maintenance "Maintenance starts at 20:00 UTC" \
--level warning --expires-at 2026-08-20T22:00:00Z
pixi-pfx channel update-notice my-channel maintenance "Maintenance moved to 21:00 UTC" --level warning
pixi-pfx channel delete-notice my-channel maintenanceThe argument after the channel is the stable notice id. --level is info (default), warning or critical, and --expires-at takes an RFC 3339 timestamp. See Channel notices for where notices are displayed.
Packages
# search by name, ordered by similarity
pixi-pfx package search numpy --limit 10
# package details, including variants
pixi-pfx package get conda-forge numpy --variants-limit 5
# list with a name filter
pixi-pfx package list --name-contains scipy --order-by name
# resolve a matchspec (--channel is required and may be repeated)
pixi-pfx package matchspec "numpy>=2.0" --channel conda-forge
# a single variant, and all versions of a package
pixi-pfx package variant conda-forge numpy linux-64 numpy-2.0.0-py312h1234.conda
pixi-pfx package versions conda-forge numpy --limit 10package list orders by name, last-created-date or total-size; search, list and versions all take --limit and --page.
Yank and delete
pixi-pfx package yank my-channel linux-64 pkg-1.0.conda --reason "broken build"
pixi-pfx package unyank my-channel linux-64 pkg-1.0.conda
pixi-pfx package batch-yank my-channel --reason "broken builds" \
--entries '[{"subdir":"linux-64","filename":"pkg-1.0.conda"}]'
pixi-pfx package batch-unyank my-channel \
--entries '[{"subdir":"linux-64","filename":"pkg-1.0.conda"}]'
pixi-pfx package batch-delete my-channel \
--entries '[{"subdir":"linux-64","filename":"pkg-1.0.conda"}]'Yanking keeps the file but hides it from solvers; batch-delete removes variants permanently. batch-yank also takes --also-hide to hide the variants from package listings as well. See Manage package and channel lifecycle for what each state means.
Copy packages into a channel
Copying is a beta-only feature for now, so these commands need --endpoint https://beta.prefix.dev/api/graphql. Copying between channels resolves every matching source variant and submits it to an asynchronous copy job:
pixi-pfx --endpoint https://beta.prefix.dev/api/graphql package copy-from-channel \
destination-channel source-channel numpy scipy
# narrow the selection
pixi-pfx --endpoint https://beta.prefix.dev/api/graphql package copy-from-channel \
destination-channel source-channel numpy --version 2.3.0 --platform linux-64
# resolve URLs and hashes without starting the job
pixi-pfx --endpoint https://beta.prefix.dev/api/graphql package copy-from-channel \
destination-channel source-channel numpy --dry-runPackages can also be pulled from arbitrary URLs. Each entry pins a url together with its expected sha256, so the copy either reproduces exactly that file or fails:
pixi-pfx --endpoint https://beta.prefix.dev/api/graphql package copy my-channel \
--package 'https://prefix.dev/conda-forge/linux-64/pkg-1.0.conda=<64-hex-sha256>' --wait
# JSON input remains available for scripts
pixi-pfx --endpoint https://beta.prefix.dev/api/graphql package copy my-channel \
--packages '[{"url":"https://prefix.dev/conda-forge/linux-64/pkg-1.0.conda","sha256":"<64-hex-sha256>"}]'Follow a job by id, or inspect any active background job for a channel. With --wait the command reports changed status and counts on stderr and prints the final per-item results:
pixi-pfx --endpoint https://beta.prefix.dev/api/graphql job get <job-id> --wait
pixi-pfx --endpoint https://beta.prefix.dev/api/graphql job active my-channelAPI keys
pixi-pfx auth api-key list
pixi-pfx auth api-key create my-key --description "CI key" --expires-at 2026-12-31T00:00:00Z
pixi-pfx auth api-key create upload-key --access-mode read-write --channel my-channel
pixi-pfx auth api-key revoke my-key
pixi-pfx auth api-key delete my-keyThe key value is only shown once, on creation, so store it right away. --channel scopes a key to one channel and requires --access-mode. Revoking disables the key but keeps the record; deleting removes it entirely.
Scripts and agents
describe prints the command tree (subcommands, arguments, types and help text) as JSON, so a script or an agent can discover the available commands without parsing --help. It always emits JSON, with or without --json:
# a single command
pixi-pfx describe channel get
# the whole tree, including the global flags
pixi-pfx describeTogether with --json, a script can discover the commands, run one and read the result from the envelope.
pixi-pfx --json channel get conda-forge | jq '.data.base_url'Next steps
GraphQL API: the API behind every command, with an interactive explorer.
API and API keys: tokens, scopes and the upload API.
Create and configure a channel: the same settings in the web UI.