Metadata-Version: 2.4
Name: quail-cli-core
Version: 0.2.0
Summary: Instrument-agnostic CLI driver contract, runtime, conformance checker, and scaffold
License-Expression: MIT
Project-URL: Repository, https://github.com/BB-84C/quail-cli-core
Keywords: scientific-instruments,cli,agent,automation,driver
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: black>=24.8.0; extra == "dev"
Requires-Dist: build>=1.2.2; extra == "dev"
Requires-Dist: mypy>=1.11.0; extra == "dev"
Requires-Dist: pytest>=8.3.0; extra == "dev"
Requires-Dist: ruff>=0.6.0; extra == "dev"
Requires-Dist: tomli>=2.0; python_version < "3.11" and extra == "dev"
Requires-Dist: twine>=5.1.1; extra == "dev"
Dynamic: license-file

# quail-cli-core

`quail-cli-core` is an instrument-agnostic CLI driver kit. It provides a shared command contract, a Python runtime, an external conformance checker, and a project scaffold for wrapping an API-accessible controller or instrument as a CLI driver compatible with the Quailbot schema.

Repository: https://github.com/BB-84C/quail-cli-core

## Project boundaries

These projects have separate responsibilities.

| Project | Responsibility |
| --- | --- |
| [quail-cli-core](https://github.com/BB-84C/quail-cli-core) | Defines the five-command driver contract and provides the runtime, conformance checker, and scaffold. |
| [nspmctl](https://github.com/BB-84C/NanonisSPMController-CLI) | A concrete Nanonis driver used by Quailbot and a reference implementation of the shared five-command model. |
| [Quailbot](https://github.com/BB-84C/quailbot-pi) | Consumes compatible drivers as an upper-level agent harness. It owns workspace capability declarations, forced linked readback, default-deny checks for state-changing operations, and the append-only experiment log. |

A driver can use any executable name, such as `nspmctl`, `laserctl`, or `scopectl`, while preserving the common contract.

## Core commands

Every compatible driver exposes these five commands.

- `capabilities` describes parameters, actions, command mappings, and capability or safety metadata.
- `get <parameter>` reads one parameter.
- `set <parameter> [<value>] [--arg key=value ...] [--interval-s <sec>] [--plan-only]` writes or plans a write.
- `ramp <parameter> <start> <end> <step> --interval-s <sec> [--plan-only]` executes or plans an explicit ramp.
- `act <action_name> [--arg key=value ...] [--plan-only]` invokes or plans an instrument action.

JSON is the default output format. Drivers may also expose `--text` for human-readable output.

Examples:

```powershell
laserctl capabilities
laserctl get wavelength_nm
laserctl set wavelength_nm 532 --plan-only
laserctl ramp power_mw 0 10 1 --interval-s 0.1 --plan-only
laserctl act Shutter_Open --plan-only
```

## Contract and conformance

The contract reference is [docs/contract-v1.md](docs/contract-v1.md). The executable `quail-cli-conformance` checker is the implementation-consistency check for external drivers.

The checker currently requires the following shapes.

- `capabilities` has exactly two top-level objects named `parameters` and `action_commands`. Each contains exactly `count` and `items`, and each count must match the length of its item list.
- Every parameter item requires the eight core keys `name`, `label`, `readable`, `writable`, `has_ramp`, `get_cmd`, `set_cmd`, and `safety`. The optional `scalar_strategy` and `scalar_coordinate` keys are accepted as a pair of non-empty strings. Other keys remain invalid.
- The `get_cmd`, `set_cmd`, and `safety` descriptors accept an object or `null`. A readable parameter requires an object-valued `get_cmd`, and a writable parameter requires an object-valued `set_cmd`. Object-valued descriptors retain strict field validation.
- Every action item includes `name`, `action_cmd`, and `safety_mode`. The allowed safety-mode values are `alwaysAllowed`, `guarded`, and `blocked`.
- Successful `get`, `set`, `ramp`, and `act` calls use the exact payload keys documented in the contract reference.
- The checker exercises an invalid-parameter call and verifies its JSON error payload and matching process exit code. This check covers that tested failure path rather than every possible argument-parser or backend failure.
- The checker appends `--json` whenever it invokes a target driver command. A compatible driver must accept this option even when JSON is already its default output format.

The 0.2.0 checker covers the capability extensions used by `nspmctl` 0.3, including paired scalar metadata and nullable descriptors. `quail-cli-core` validates capability and safety metadata structure. It does not execute the safety policy described by that metadata.

Run the checker with real parameters and actions from the target driver. Mutation-capable checks use `--plan-only`. This is not an offline mode. A concrete driver may still connect to its backend, read current state, or require writes to be enabled. `nspmctl` has these requirements.

```powershell
quail-cli-conformance `
  --command "laserctl" `
  --get-parameter wavelength_nm `
  --set-parameter wavelength_nm `
  --set-value 532 `
  --ramp-parameter power_mw `
  --ramp-start 0 `
  --ramp-end 10 `
  --ramp-step 1 `
  --action-name Shutter_Open
```

## Install quail-cli-core 0.2.0

```powershell
python -m pip install quail-cli-core
quail-cli-bootstrap --help
quail-cli-conformance --help
```

## Scaffold a driver

Generate a standalone driver project:

```powershell
quail-cli-bootstrap `
  --output-dir D:\drivers\laserctl `
  --cli-name laserctl `
  --package-name laser_driver `
  --project-name laser-instrument-driver
```

The scaffold separates the instrument backend from the contract-facing driver. Replace its placeholder backend with calls to the real controller API, then verify the resulting project. Scaffold generation alone is not conformance evidence.

```powershell
Set-Location D:\drivers\laserctl
python -m pip install -e ".[dev]"
pytest
quail-cli-conformance `
  --command "laserctl" `
  --get-parameter instrument_value `
  --set-parameter instrument_value `
  --set-arg Value=0.2 `
  --ramp-parameter instrument_value `
  --ramp-start 0 `
  --ramp-end 0.4 `
  --ramp-step 0.1 `
  --action-name Instrument_Action `
  --action-arg Mode=1
```

## Included components

- `quail_cli_core.driver` defines the abstract interface for the five core operations.
- `quail_cli_core.runtime` provides the shared parser, dispatch, JSON serialization, and handled-error output paths.
- `quail_cli_core.conformance` checks an external driver process against the implemented contract.
- `quail_cli_core.scaffold` generates a starting driver project.
- `examples/minimal_demo_driver.py` provides a minimal implementation example.
- `docs/contract-v1.md` documents the `core-v1` command and payload contract.

## What this kit does not do

`quail-cli-core` does not connect to a specific instrument by itself. Each concrete driver owns its controller API integration, state handling, and execution policy.

The kit declares and validates the structure of capability and safety metadata. It does not enforce limits such as minimum values, maximum values, step limits, or cooldowns. A concrete driver must implement and verify any policy represented by that metadata.

The kit also does not provide Quailbot's workspace capability declarations, forced linked readback, default-deny checks for state-changing operations, or append-only experiment log. Those are upper-level harness responsibilities in [Quailbot](https://github.com/BB-84C/quailbot-pi).
