Metadata-Version: 2.4
Name: ldv-cli
Version: 0.12.0
Summary: ldv — CLI for the Liquid DataViewer platform (formerly lql)
Project-URL: Homepage, https://github.com/Liquid4All/lql
Author: Liquid AI
License: MIT
Requires-Python: >=3.12
Requires-Dist: httpx>=0.27
Requires-Dist: huggingface-hub>=0.24
Requires-Dist: rich>=13.0
Requires-Dist: textual-image>=0.7
Requires-Dist: textual>=0.50
Requires-Dist: typer>=0.12
Description-Content-Type: text/markdown

# ldv — Liquid DataViewer CLI

Scriptable CLI for the [Liquid DataViewer](https://dataviewer.liquid.ai) platform. Designed for both humans and AI agents (Claude Code, Codex, etc.) to automate datasets, eval analysis, spec docs, annotations, and more.

A Python package (Python ≥ 3.12), published on PyPI as **[`ldv-cli`](https://pypi.org/project/ldv-cli/)** — the installed command is `ldv`.

> **Renamed from `lql`.** This CLI was formerly published as `lql-cli` with an `lql` command. The `lql` command still works as an alias, and the legacy `LQL_*` environment variables and `~/.lql/config.json` are still honored, so existing setups keep working. New users should install `ldv-cli` and use `ldv`.

## Quick start

```bash
uv tool install ldv-cli               # install the CLI (or: pipx install ldv-cli); the command is `ldv`
ldv login                             # authenticate (opens a browser)
ldv skills install                    # teach Claude Code + Codex how to use ldv
```

## Install

`ldv` is a Python package (requires Python ≥ 3.12), distributed on PyPI as **`ldv-cli`** (the
command it installs is `ldv`). Install it as a standalone CLI tool with
[uv](https://docs.astral.sh/uv/):

```bash
uv tool install ldv-cli
```

Or with pipx / pip:

```bash
pipx install ldv-cli
# or
pip install ldv-cli
```

Run it without installing:

```bash
uvx --from ldv-cli ldv instructions
```

Or build from source:

```bash
git clone https://github.com/Liquid4All/ldv
cd ldv
uv tool install .     # or: pip install -e .
```

Update to the latest version with `ldv update --run`, which detects how ldv was
installed (uv tool / pipx / pip) and runs the matching upgrade. Run `ldv update`
(no flag) to just print the command without executing it.

## Authentication

### Interactive login (browser)

```bash
ldv login
```

Opens a browser window. After authorizing, credentials are saved to `~/.ldv/config.json`.

### Non-interactive (API key)

```bash
export LDV_API_KEY=ak_live_...
ldv login         # stores key in config
# or skip config entirely — just set the env var
```

### Logout

```bash
ldv logout
```

## Environment variables

| Variable | Description |
|---|---|
| `LDV_API_KEY` | API token (bypasses config file) |
| `LDV_API_URL` | Override API base URL |
| `LDV_HF_TOKEN` | HuggingFace token (required for `datasets upload`) |
| `LDV_EVAL_WORKSPACE` | Default workspace for `eval list` |
| `LDV_ALLOW_INSECURE_API_URL` | Set to `1` to allow a plaintext `http://` API URL to a non-loopback host (off by default — the token is only sent over HTTPS or to localhost) |

## Command reference

Running a group with no subcommand (e.g. `ldv datasets`) lists its subcommands.
For faster typing, **aliases** and **unique prefixes** resolve everywhere:
group aliases (`ds`, `ws`, `ev`, `ann`, `hl`, `rep`, `bkt`, `iss`), verb aliases
(`ls`=list, `rm`/`del`=delete, `new`/`mk`=create, `info`=show), and prefixes
(`ldv datasets l` → `list`). So `ldv ds ls --workspace <id>` ≡ `ldv datasets list
--workspace <id>`. The canonical names below always work (use those in scripts).

### Auth

```
ldv login                        Authenticate (browser or LDV_API_KEY)
ldv logout                       Revoke key and clear profile
ldv whoami                       Show current user
```

### Workspaces

```
ldv workspaces list [--search <text>]            List workspaces (--search filters by name/slug)
ldv workspaces create <name>                     Create a workspace
ldv workspaces show <id>                         Show workspace details
ldv workspaces update <id> --name <n>            Rename a workspace
ldv workspaces delete <id>                       Delete a workspace
ldv workspaces members list <id>                 List members
ldv workspaces members add <id> <email>          Add member by email
ldv workspaces members remove <id> <uid>         Remove member by user ID
```

### Datasets

```
ldv datasets list [--workspace <id>] [--search <text>]   List datasets (--search filters by name/HF repo)
ldv datasets show <id>                           Show dataset details
ldv datasets create --workspace <id> --hf-repo <repo> [--name <n>] [--split <s>]
ldv datasets create --workspace <id> --hf-bucket <org/bucket> --key <path-or-glob> [--name <n>]
                                                 From an HF storage bucket (e.g. --key 'data/*.parquet')
ldv datasets sync <id>                           Trigger sync (HF repo, S3, or HF bucket)
ldv datasets schema <id>                         Show column schema
ldv datasets rows <id> [-f "col<op>value"] [--columns a,b] [--limit N] [--offset N]
                                                 Fetch rows (-f/--filter: same syntax everywhere)
ldv datasets delete <id>                         Delete dataset
ldv datasets push <id>                           Push to HuggingFace
ldv datasets push-status <id> [--job <id>]       Check push job status
ldv datasets upload <file> --workspace <id> --name <repo-name> [--split <s>]
                                                 Upload local file → HF → dataset
```

`datasets upload` requires `LDV_HF_TOKEN`.

### Preview

View dataset samples in the terminal — a Textual TUI with a chat-style layout
(user turns on the right, system/assistant/tool on the left). It renders the
same formats as the DataViewer web UI: OpenAI `{role, content}`, structured/
multimodal content (text/image/audio), ShareGPT `{from, value}`, native OpenAI
`tool_calls`, plus `<think>` reasoning blocks, `<|tool_call_start|>…<|tool_call_end|>`
/ Python / XML / JSON tool calls, tool results, tool-definition tables, and code.

Works on a local `.jsonl`/`.json` file, a platform dataset ID, or — with `--hf`
— a HuggingFace repo. No browser, and nothing to forward over SSH — it's just
the terminal.

```
ldv preview <file.jsonl|file.json>     Local file: each line/object is a row
ldv preview <dataset-id>               Platform dataset (fetched & paged lazily)
ldv preview <org/name> --hf            HuggingFace repo: sync to DataViewer, then view
ldv preview <src> -c <field>           Force field(s) as conversations (repeatable)
ldv preview <src> -f "col=value"       Filter rows (repeatable, AND); local & platform
ldv preview <src> -n <N>               Page size when paging a platform dataset
ldv preview <src> --offset N           Start at row index N
ldv preview <src> --title "<title>"    Title shown in the viewer header
```

**Filtering (`--filter`/`-f`) — one syntax everywhere.** The same flag and syntax
work on `preview`, `datasets rows`, and `eval samples`. Show only matching rows —
`preview` also filters local files (client-side); platform datasets filter
server-side. Repeatable; filters AND together; string match is case-insensitive.
Operators: `=`, `!=`, `~` (contains), `>`, `<`, `>=`, `<=`.

```
ldv preview <dataset-id> -f "domain=telecom"
ldv preview data.jsonl -f "reward>=0.8" -f "split=test"     # both must hold
ldv preview <dataset-id> -f "model~lfm"                      # contains
```

**HuggingFace datasets (`--hf`).** `ldv preview org/name --hf` syncs the repo
into a DataViewer workspace, then opens it. You pick the target workspace from
an interactive list (or pass `--workspace <id>`; `--split` defaults to `train`).
Already-synced repos are reused — no duplicate, instant re-open.

```
ldv preview tatsu-lab/alpaca --hf
ldv preview org/name --hf --split validation --workspace <id>
```

**Media.** Images render **inline** in terminals that support an image protocol
(Kitty/Ghostty, iTerm2, Sixel; falls back to a compact `🖼 …` placeholder
elsewhere) — both multimodal `image_url`/data-URI segments and image-mode
columns. Audio can't play inline in a terminal, so each clip shows a `♪` line
and **`p` plays** the current sample's audio via the system player (`afplay`/
`open`). Images render inline in pager mode (one sample at a time); scroll mode
shows placeholders to avoid decoding the whole buffer.

**Navigation** — two modes, toggle with `m`:

- **pager** (default): one sample at a time · `←/→` or `n`/`b` switch samples · `↑/↓`/`j`/`k`/PgUp-Dn scroll
- **scroll**: all samples in one buffer · `n`/`b` jump between samples · arrows scroll
- **copy**: `Tab`/`Shift+Tab` move a highlight between blocks · `c` copies the focused message/field · `Y` copies the whole sample as JSON (via OSC 52 — reaches your **local** clipboard over SSH where the terminal supports it, e.g. Ghostty/iTerm2; not macOS Terminal)
- `p` play audio · `q` quits

```
ldv preview examples/agent-traces.jsonl     # 20-sample file of agent-trace/tool-use formats
ldv preview <dataset-id>                     # browse a platform dataset, paged on demand
```

### Evals (dataset analysis)

Eval datasets are evaluation-run output — each row a sample with a model
`response` and a `correct` verdict. They're detected automatically. These
commands are the data primitives for error analysis: they slice and summarize
the dataset, and you do the reasoning over what they return.

```
ldv eval list [--workspace <id>] [--runid <id>] [--taskid <id>]
                                                 List eval datasets only. --runid/--taskid filter by
                                                 run<id>/task<id> in the name or parquet storage path
                                                 (e.g. run11213_task72284.parquet); they AND together.
                                                 Defaults to LDV_EVAL_WORKSPACE; without a
                                                 workspace, lists only evals you own.
ldv eval correctness <id>                        Fast accuracy + correct/incorrect/missing counts
ldv eval stats <id>                              Accuracy + error-type distribution + token stats
ldv eval samples <id> [-f "col<op>value" ...] [--correct|--incorrect|--missing]
                       [--search <text>] [--error-type <value>]
                       [--columns a,b] [--limit N] [--offset N]
                                                 Slice the dataset for error analysis. Filters
                                                 AND together; prints an `index` column per row.
ldv eval sample <id> --row <index>               Read one full sample (the conversation) by the
                                                 `index` returned from `eval samples`
```

Notes:

- `-f`/`--filter` is the unified column filter — same syntax as `preview` and `datasets rows` (see Filtering above).
- `--correct` / `--incorrect` / `--missing` are convenience flags for the canonical correctness filter (mutually exclusive). They AND with any `-f` filters, `--search`, and `--error-type`.
- `--search` matches a substring on the prompt **or** response column (either hit counts). Override the searched columns with `--search-columns a,b`.
- `--error-type` values come from the `error_field` / `error_distribution` reported by `eval stats`.
- Use the `index` from `eval samples` directly as `eval sample --row <index>`.

Typical analysis loop:

```bash
ldv eval list --workspace <id>                   # find the eval dataset
ldv eval stats <id>                              # accuracy + where the errors cluster
ldv eval samples <id> --incorrect --limit 20     # pull the misses
ldv eval samples <id> --incorrect -f "reasoning_tokens>30000"  # misses that ran long
ldv eval sample <id> --row 42                    # read one failure in full
```

### Edits

```
ldv edits list <dataset_id> [--limit N]          List edits
ldv edits count <dataset_id>                     Count edits
ldv edits add <dataset_id> --row <ext_id> --column <col> --value <json>
ldv edits delete <dataset_id> <edit_id>          Delete an edit
```

### Spec docs

```
ldv spec show --workspace <id>                   Show current spec doc
ldv spec pull --workspace <id> [-o <file>] [--stdout]
                                                 Pull markdown (writes SPEC.md by default)
ldv spec push --workspace <id> [--file <f>] --message <m> [--base-version-id <id>]
                                                 Defaults --file to SPEC.md; --message required
ldv spec history --workspace <id>                Version history
ldv spec diff --workspace <id> --version-id <id> [--compare-to <id>]
ldv spec generate --workspace <id>               AI-generate a spec from the workspace's datasets
```

`push` auto-detects create-vs-update: with no existing doc it creates v1, otherwise it commits on
top of the current HEAD (auto-resolved unless `--base-version-id` is given). On conflict (409),
`spec push` exits with code 4 — pull again, re-apply, and push.

### Review (annotations, highlights, issues, reports)

These act directly on a **dataset** — the CLI resolves the dataset's review session for you, so you
never manage sessions by hand. Advanced: pass `--session <id>` to target a specific session for
multi-pass review (a session id is returned in the JSON of any annotation/highlight/report).

#### Annotations

```
ldv annotations list <dataset_id> [--session <id>]
ldv annotations add <dataset_id> --row <ext_id> [--rating <n>] [--note <str>] [--session <id>]
```

#### Highlights

Highlights mark a text span (`--start`/`--end` are character offsets into the row's `--column` value).

```
ldv highlights list <dataset_id> [--session <id>]
ldv highlights add <dataset_id> --row <ext_id> --column <col> --start <n> --end <n> --text <str>
                  [--issue <id>] [--color <hex>] [--note <text>] [--session <id>]
```

#### Issues

A per-dataset taxonomy (name/color) used to tag highlights via `highlights add --issue <id>`.

```
ldv issues list <dataset_id>
ldv issues create <dataset_id> --name <str> [--description <str>] [--color <hex>]
```

#### Reports

```
ldv reports list <dataset_id> [--session <id>]
ldv reports show <report_id>                     Show a report
ldv reports create <dataset_id> --title <title> [--summary <text>] [--session <id>]
                                                 Publish a report (bundles annotations + LLM analysis)
```

### Buckets

S3-compatible:

```
ldv buckets list                                 List S3 buckets
ldv buckets show <id>                            Show bucket details
ldv buckets probe <id>                           Test bucket connectivity + credentials
ldv buckets objects <id> [--prefix <str>]        List objects
ldv buckets attach <bucket_id> --workspace <id>  Attach bucket to workspace
ldv buckets detach <bucket_id> --workspace <id>  Detach bucket from workspace
```

Hugging Face buckets (connect → add datasets; auth is your HF token):

```
ldv buckets list-hf                              List HF bucket connections
ldv buckets connect-hf <owner/bucket> --workspace <id> [--label <l>] [--hf-key <id>]
                                                 Connect an HF bucket and attach it to a workspace
ldv buckets create-dataset <bucket_id> --workspace <id> --key <path-or-glob> [--name <display>]
                                                 Create a dataset from a connected HF bucket
```

### Skills (agent setup)

Install the `ldv` agent skill so coding agents (Claude Code, Codex) know how to use ldv. The skill
is a thin pointer that tells the agent to run `ldv instructions`, so it never goes stale.

```
ldv skills install [--tool claude|codex|both] [--project] [--force]
                                                 Install to ~/.claude and ~/.codex (both, by default)
ldv skills uninstall [--tool claude|codex|both] [--project]
```

`--project` installs into `./.claude` and `./.codex` in the current directory instead of the home dir.

### Instructions

```
ldv instructions                                 Print the full agent reference (all commands,
                                                 flags, examples, and workflows) in one read
```

### Update

```
ldv update                                       Detect install method (uv/pipx/pip), print upgrade cmd
ldv update --run                                 Detect and run the upgrade in place
```

## Global flags

All commands accept:

| Flag | Description |
|---|---|
| `--json` | Output raw JSON to stdout |
| `--profile <name>` | Use a named config profile |
| `--api-url <url>` | Override the API base URL |

## Exit codes

| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Unauthenticated / forbidden |
| 3 | Not found |
| 4 | Conflict (e.g. spec push version conflict) |
| 5 | Server error |

## Config file

`~/.ldv/config.json` (mode 0600):

```json
{
  "current_profile": "default",
  "profiles": {
    "default": {
      "token": "ak_live_...",
      "key_id": "uuid",
      "api_url": "https://liquid-anchor-api.fly.dev"
    }
  }
}
```
