# QRM

CLI + Python client for interacting with the Qestit QRM.

## Install

```bash
pip install lr-qrm
```

## Quick start

### Login

Interactive login (prompts for username/password):

```bash
qrm login --base-url https://example.com
```

Non-interactive (for CI/CD):

```bash
export QRM_USERNAME="<insert username>"
export QRM_PASSWORD="<insert password>"
qrm login --ci --base-url https://example.com
```

By default, this stores session details at:

```
~/.config/qrm/login.json
```

### Commands

#### Check API health

```bash
qrm status
```


#### Query production test results

##### By date range

```bash
qrm query results --start "2026-03-01T00:00:00Z" --stop "2026-03-01T23:59:59Z"
qrm query results --output json
```

Retrieves all production test results in the given date range (defaults to today if not specified). Output is a rich table by default, or JSON with `--output json`. References (operator, station, test program, etc.) are resolved for readability.

##### By serial number

```bash
qrm query serial 326115020010F2F1
qrm query serial 326115020010F2F1 --output json
```

Retrieves all test results for a given serial number. Output is a rich table by default, or JSON with `--output json`. References are resolved.

All `query` subcommands are read-only and accept global options like `--config-path`, `--base-url`, `--insecure`, and `--output`.

#### Production Box Management

##### List production boxes

```bash
qrm box list --stop "2026-02-06T23:59:00Z"
```

If you omit `--start`, the command defaults to the Unix epoch (`1970-01-01T00:00:00Z`). Leave `--stop` out to let QRM use its current time.

##### Get detailed box information

```bash
qrm box get BOX-12345
```

Shows detailed information about a specific box and lists all items it contains.

##### Create a production box

```bash
qrm box create BOX-12345 \
  --started "2026-02-01T00:00:00Z" \
  --finished "2026-02-06T23:59:00Z" \
  --units 10 \
  --shipped
```

Creates or updates a production box with manufacturing dates and unit count. Use `--shipped` to mark the box as shipped.

##### Update an existing box

```bash
qrm box update BOX-12345 --units 12 --finished "2026-02-07T12:00:00Z"
```

Updates properties of an existing production box.

##### Delete a production box

```bash
qrm box delete BOX-12345
```

Deletes a production box. This command is idempotent and will not fail if the box is already deleted.

##### Add an item to a box

```bash
qrm box add-item BOX-12345 --serial-number "326115020010F2F1"
```

Adds an item to a production box. You can identify the item by serial number, type name, or identifier tag.

##### Remove an item from a box

```bash
qrm box remove-item BOX-12345 --serial-number "326115020010F2F1"
```

Removes an item from a production box. Supports serial number, type name, or identifier tag for identification.

##### Find a box containing a specific item

```bash
qrm box find --serial-number "326115020010F2F1"
```

Searches for the production box containing a specific item by serial number, type name, or identifier tag.

#### JSON output

Most commands support a JSON output mode.

```bash
qrm uut status 326115020010F2F1 --output json
```

## Programmatic use

```python
from qrm.config import load_login_state
from qrm.client import QrmClient

state = load_login_state()
client = QrmClient(base_url=str(state.base_url), verify_tls=state.verify_tls)

uut_runs = client.uut_status(
    token=state.token,
    serial_number="326115020010F2F1",
    start_datetime="2026-02-01T00:00:00Z",
    stop_datetime="2026-02-06T23:59:00Z",
    max_results=1000,
)

boxes = client.box_list(
    token=state.token,
    start_datetime="1970-01-01T00:00:00Z",
    stop_datetime="2026-02-06T23:59:00Z",
)

# Get detailed box information
box = client.box_get(
    token=state.token,
    box_identifier="BOX-12345",
)

content = client.box_content(
    token=state.token,
    box_identifier="BOX-12345",
)

# Create a production box
new_box = client.box_add(
    token=state.token,
    box_identifier="BOX-12345",
    started_datetime="2026-02-01T00:00:00Z",
    finished_datetime="2026-02-06T23:59:00Z",
    number_of_units=10,
    shipped=True,
)

# Delete a production box
result = client.box_remove(
    token=state.token,
    box_identifier="BOX-12345",
)

# Add an item to a box
result = client.box_uut_add(
    token=state.token,
    box_identifier="BOX-12345",
    uut_serial_number="326115020010F2F1",
)

# Remove an item from a box
result = client.box_uut_remove(
    token=state.token,
    box_identifier="BOX-12345",
    uut_serial_number="326115020010F2F1",
)

# Find which box contains a specific item
box = client.box_find(
    token=state.token,
    uut_serial_number="326115020010F2F1",
)
```


## FAQ

- **Where is the config kept?**
  `~/.config/qrm/login.json` (override with `QRM_CONFIG`)

- **How do I run non-interactively?**
  Make sure to give all required arguments. Also pass `--ci` to stop output of sensitive information such as username or passwords.

---

## AI assistant integration

`lr-qrm` ships a bundled skill/instruction file that teaches AI coding assistants
about the CLI commands, Python API, data models, and common workflows.

Run this once from the root of your project:

```bash
qrm --install-skill
```

This does three things:

- **Claude Code** — copies the skill to `~/.claude/skills/lr-qrm/` (global, available in all projects)
- **GitHub Copilot** — writes `.github/instructions/lr-qrm.instructions.md` in the current directory
- **VSCode** — sets `github.copilot.chat.codeGeneration.useInstructionFiles: true` in `.vscode/settings.json` (creates the file if it doesn't exist; merges if it does)

To inspect the skill content without installing:

```bash
qrm --show-skill
```