Metadata-Version: 2.5
Name: pixi-browse
Version: 0.0.20
Summary: A TUI to browse conda packages
Project-URL: repository, https://github.com/pavelzw/pixi-browse
Author-email: Pavel Zwerschke <pavelzw@gmail.com>
License-File: LICENSE
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.13
Requires-Dist: py-rattler<0.28,>=0.27.0
Requires-Dist: pyyaml<7,>=6.0.3
Requires-Dist: textual<9,>=8.2.8
Requires-Dist: typer<0.28,>=0.27.2
Provides-Extra: diff
Requires-Dist: textual-diff-view<0.2,>=0.1.5; extra == 'diff'
Provides-Extra: filetype
Requires-Dist: python-magic<0.5,>=0.4.27; extra == 'filetype'
Description-Content-Type: text/markdown

# pixi-browse

[![CI](https://img.shields.io/github/actions/workflow/status/pavelzw/pixi-browse/ci.yml?style=flat-square&branch=main)](https://github.com/pavelzw/pixi-browse/actions/workflows/ci.yml)
[![conda-forge](https://img.shields.io/conda/vn/conda-forge/pixi-browse?logoColor=white&logo=conda-forge&style=flat-square)](https://prefix.dev/channels/conda-forge/packages/pixi-browse)
[![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/pixi-browse?style=flat-square)](https://prefix.dev/channels/conda-forge/packages/pixi-browse)
[![pypi-version](https://img.shields.io/pypi/v/pixi-browse.svg?logo=pypi&logoColor=white&style=flat-square)](https://pypi.org/project/pixi-browse)
[![python-version](https://img.shields.io/pypi/pyversions/pixi-browse?logoColor=white&logo=python&style=flat-square)](https://pypi.org/project/pixi-browse)

An interactive terminal UI for browsing conda package metadata.
Explore packages, versions, dependencies, and more from any conda channel — right from your terminal.

![pixi-browse demo](https://raw.githubusercontent.com/pavelzw/pixi-browse/refs/heads/main/.github/assets/demo-dark.gif#gh-dark-mode-only)
![pixi-browse demo](https://raw.githubusercontent.com/pavelzw/pixi-browse/refs/heads/main/.github/assets/demo-light.gif#gh-light-mode-only)

## Features

- **Browse packages** from any conda channel (conda-forge, prefix.dev, etc.)
- **Substring search** to quickly filter through thousands of packages, as well as through a package's versions, dependencies and files
- **Inspect versions** grouped by platform with collapsible sections
- **View detailed metadata** including dependencies, license, checksums, build info, and timestamps
- **Inspect package contents** — file listings and `about.json` extracted directly from artifacts
- **Spot repodata patches** — diff an artifact's original `index.json` against the patched repodata served by the channel
- **Verify Sigstore attestations** — see who built a signed artifact, from which workflow and ref, and whether the signature binds to this exact file and channel
- **Compare artifacts** — metadata, dependencies, and file lists of two builds side by side, with optional file diffs
- **Terminal hyperlinks** to source repositories, maintainer GitHub profiles, and provenance commits
- **Download artifacts** directly to your working directory
- **Vim-style keybindings** for fast keyboard-driven navigation

## Installation

### From conda-forge

```bash
pixi global install pixi-browse
# or use without installation
pixi exec pixi-browse
```

### From PyPI

```bash
uv tool install pixi-browse
# or use without installation
uvx pixi-browse
```

### Optional: file diffs

Comparing two artifacts (`C`) can show a side-by-side diff of a file that
differs between them. This uses
[textual-diff-view](https://github.com/batrachianai/textual-diff-view), which is
AGPL-3.0 licensed and therefore not installed by default:

```bash
pixi global install 'pixi-browse[extras=diff]'
pixi exec -s 'pixi-browse[extras=diff]' pixi-browse

# or from PyPI
uv tool install 'pixi-browse[diff]'
uvx 'pixi-browse[diff]'
```

Without it, the `Diff left / right` action in the compare view asks for this
package.

### Optional: file types

The file action dialog always says whether a file is text or binary. With
[python-magic](https://github.com/ahupp/python-magic) installed it also names
the type the way `file` does, e.g. `Python script` or `ELF 64-bit LSB shared
object, x86-64`. python-magic needs the native libmagic library, so it is not
installed by default:

```bash
pixi global install 'pixi-browse[extras=filetype]'
pixi exec -s 'pixi-browse[extras=filetype]' pixi-browse

# or from PyPI
uv tool install 'pixi-browse[filetype]'
uvx 'pixi-browse[filetype]'
```

Pixi installs libmagic along with it. From PyPI the library has to be installed
separately: `brew install libmagic`, `apt install libmagic1`, or, on Windows, a
libmagic DLL and its magic database.

Without either, the dialog only says `text` or `binary`.

## Usage

```bash
# Browse configured default channels (conda-forge if unset) across all platforms
pixi-browse

# Read a specific config file
pixi-browse --config ./config.toml

# Browse a different channel
pixi-browse -c https://prefix.dev/conda-forge

# Browse several channels at once
pixi-browse -c conda-forge -c bioconda

# Restrict to specific platforms
pixi-browse -p linux-64 -p osx-arm64

# Start with a MatchSpec query applied
pixi-browse -m "numpy >=2"

# Combine channel, platform, and MatchSpec filters
pixi-browse -c https://prefix.dev/conda-forge -p linux-64 -m "python >=3.13"

# Show version
pixi-browse --version
```

### CLI Options

| Option              | Description                                                           |
| ------------------- | --------------------------------------------------------------------- |
| `-c`, `--channel`   | Startup channels (repeat for multiple; overrides configured defaults) |
| `--config`          | Config file to read instead of the default locations                  |
| `-p`, `--platform`  | Platforms to include (repeat for multiple)                            |
| `-m`, `--matchspec` | MatchSpec query to apply at startup                                   |
| `--version`         | Show version and exit                                                 |
| `--help`            | Show help and exit                                                    |

### Configuration

Without `--config`, pixi-browse loads Pixi's default configuration locations
through rattler, including shared rattler configuration. These include system
configuration, the platform's user configuration directory (and
`XDG_CONFIG_HOME`), and `$PIXI_HOME/config.toml` or `~/.pixi/config.toml`.
Later files override earlier ones; missing default files are skipped.
`--config <path>` reads only that file and reports missing or invalid files.

```toml
default-channels = ["conda-forge", "bioconda"]

[mirrors]
"https://conda.anaconda.org/conda-forge" = ["https://prefix.dev/conda-forge"]

[repodata-config]
disable-sharded = true
```

The shared network client applies mirrors, S3 options, authentication, proxy,
and TLS settings to repodata, package previews, and downloads. Repodata format
settings (including per-channel overrides) and `concurrency.downloads` are
applied to the gateway. Who-needs queries scan the full channel repodata,
even when sharded repodata is enabled for browsing.

Explicit `-c` flags replace `default-channels`. If neither is set, pixi-browse
uses `conda-forge`.

## Keybindings

### Navigation

| Key                 | Action                        |
| ------------------- | ----------------------------- |
| `j` / `k`           | Move selection or scroll      |
| `h` / `l`           | Focus left / right pane       |
| `gg` / `G`          | Jump to top / bottom          |
| `Ctrl+u` / `Ctrl+d` | Page up / down                |
| `Enter`             | Open / select                 |
| `Esc`               | Back or close current overlay |

### App

| Key | Action                                            |
| --- | ------------------------------------------------- |
| `?` | Show help                                         |
| `/` | Search packages, versions, dependencies, or files |
| `p` | Open platform selector                            |
| `c` | Select channels                                   |
| `C` | Compare selected artifact (in versions view)      |
| `m` | Query packages with a MatchSpec                   |
| `w` | Query packages that need a package                |
| `d` | Download selected artifact (in versions view)     |
| `q` | Quit                                              |

### Channel selector

`c` opens a dialog with the channels being browsed. The package list and the
MatchSpec and who-needs queries run against all of them.

| Control              | Action                                               |
| -------------------- | ---------------------------------------------------- |
| Text field           | Type a channel name or URL, `Enter` adds it          |
| `✕` button           | Remove that channel (the last one cannot be removed) |
| `Apply` button       | Load the listed channels and the one typed, if any   |
| `Up` / `Down`, `Tab` | Move between the `✕` buttons, the field and `Apply`  |
| `Esc`                | Cancel                                               |

## Attestations

Channels can publish [Sigstore](https://www.sigstore.dev) attestations for the
packages they serve, in a sidecar next to the archive whose digest the repodata
advertises. The `Attestation` tab of the metadata section reports what verifying
one says: the signing identity (for GitHub Actions, the workflow file and the ref
it ran on), the certificate issuer, when the signature was logged, and the
channel the attestation was issued for. The tab label carries `✓` when a
signature verified and `✗` when none did, so signedness can be read without
opening the tab.

pixi-browse only reports; it never refuses to show a package. No publisher is
required, and an attestation issued for a different channel than the one the
artifact was fetched from — a mirror, say — is shown as a warning rather than
treated as a rejection. Whether that is acceptable is yours to decide. An
artifact whose channel advertises no attestations is reported as unsigned, which
costs no request.

Verifying loads the Sigstore trusted root over the network the first time, so
the tab is the one part of pixi-browse that is not satisfied by the channel
alone. Package metadata and files render as soon as the archive is available;
the attestation tab updates when those independent checks finish.

## Development

This project is managed by [pixi](https://pixi.sh).

```bash
git clone https://github.com/pavelzw/pixi-browse
cd pixi-browse

pixi run pre-commit-install
```

### Running Tests

```bash
pixi run test
```

The tests run the app against small offline conda channels (`conda-forge`,
`bioconda` and `skill-forge`) made of real artifacts listed in
`tests/fixtures/channel_artifacts.toml`.
They are downloaded into the git-ignored `tests/fixtures/channels/` directory on
first use (or ahead of time with `pixi run fetch-test-channel`) and verified by
SHA256, so later runs work offline. TUI screens are checked with
[pytest-textual-snapshot](https://github.com/Textualize/pytest-textual-snapshot).

Attestations are verified against the trusted root embedded in rattler rather
than the one its TUF repository serves, so the whole suite runs offline — no test
reaches `tuf-repo-cdn.sigstore.dev`.

The app draws in ANSI colors, so the terminal palette alone decides how it looks.
Every screen is therefore snapshotted twice from a single app run, with the two
palettes `pixi run demo` records the demos with (`rose-pine-moon` and
`rose-pine-dawn`), side by side as
`tests/__snapshots__/<module>/<test>.{dark,light}.svg`.

After an intentional UI change, review `snapshot_report.html` and accept the new
screenshots with:

```bash
pixi run snapshot-update
```

To review committed snapshot changes against `main` without rerunning the tests:

```bash
pixi run snapshot-report
```

### Linting

```bash
pixi run pre-commit-run
```
