Metadata-Version: 2.4
Name: ch-play
Version: 0.1.1
Summary: MCP orchestrator for reproducible ClickHouse workload diagnostics
Author-email: O2eg <oleg.ispu@yandex.ru>
License-Expression: MIT
Project-URL: Homepage, https://o2eg.com/
Project-URL: Repository, https://github.com/O2eg/ch_play
Project-URL: Issues, https://github.com/O2eg/ch_play/issues
Keywords: clickhouse,mcp,orchestration,diagnostics,workload
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Database
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: ch-diag<1,>=0.8.3
Requires-Dist: ch-stand<1,>=0.1.1
Requires-Dist: ch-workload<1,>=0.1.2
Requires-Dist: mcp<2,>=1.28
Requires-Dist: PyYAML<7,>=6.0
Provides-Extra: dev
Requires-Dist: build<2,>=1.2; extra == "dev"
Requires-Dist: pytest<9,>=8.3; extra == "dev"
Requires-Dist: ruff<1,>=0.12; extra == "dev"
Requires-Dist: twine<7,>=6; extra == "dev"
Dynamic: license-file

# ch_play

`ch_play` coordinates a reproducible ClickHouse experiment: it activates a declarative
`ch_stand`, optionally installs `ch_workload` profiles, runs the workload, and collects
`ch_diag` snapshots at the same time. The result is a durable run directory with JSON/HTML
diagnostic reports, the reviewed plan, component versions, state, and append-only events.

The MCP server exposes only typed experiment operations. It does not expose arbitrary SQL,
shell, SSH, or Docker commands.

## Requirements

- Linux and Docker supported by `ch_stand`;
- `ssh-keyscan` for `collection_mode: remote`;
- Python 3.10 or newer;
- compatible `ch_stand`, `ch_workload`, and `ch_diag` console commands from the same Python
  environment.

Install from PyPI after publication:

```bash
python3 -m pip install ch-play
```

For a source checkout:

```bash
python3 -m venv .venv
.venv/bin/pip install -e '.[dev]'
```

## Experiment manifest

The initial `imdb_cluster` workload requires the `4 shards x 2 replicas` profile from
`ch_stand`. Paths are resolved relative to the experiment manifest.

```yaml
api_version: ch_play/v1
kind: ClickHouseExperiment

metadata:
  id: imdb-diagnostics

spec:
  artifact_root: .ch_play/experiments/imdb-diagnostics

  stand:
    config: stand/configs/sharded-replicated-8.yaml
    project: stand
    timeout_seconds: 600

  workload:
    project: workload
    profiles: [imdb_cluster]
    database: ch_workload
    scale: 0.1
    seed: 20260802
    duration_seconds: 60
    install: true
    recreate: false
    resource_monitor: true

  diagnostics:
    collection_mode: remote
    target_scope: cluster
    interval_seconds: 5
    report_name: during-workload
```

The ClickHouse user, cluster name, HTTP/native/SSH ports, password file, and SSH key are derived
from the resolved `ch_stand` configuration. `spec.workload.database` is the database created and
loaded by the workload profile; it defaults to `ch_workload`. Passwords are forbidden in the
manifest and are never passed in process arguments or returned by MCP.

## Safe execution flow

Validate and review the exact deterministic plan first:

```bash
ch-play validate experiment.yml
ch-play plan experiment.yml
```

Pass the returned `plan_hash` unchanged. A detached run is the preferred mode for MCP clients:

```bash
ch-play start experiment.yml --plan-hash sha256:... --run-id run-001
ch-play status experiment.yml --run-id run-001
ch-play events experiment.yml --run-id run-001
```

For a foreground terminal run, use `ch-play run` with the same arguments. A cancellation request
is cooperative and is bound to the recorded experiment processes:

```bash
ch-play cancel experiment.yml --run-id run-001 --reason "enough samples"
```

The stand remains available after a completed or failed run so that it can be inspected. Removal
is always explicit:

```bash
ch-play teardown experiment.yml --run-id run-001
ch-play teardown experiment.yml --run-id run-001 --clear-data --force
```

`--clear-data` permanently removes stand data and therefore additionally requires `--force`.

## Reports

By default the run directory contains:

- `during-workload.json` and `during-workload.html` from `ch_diag`;
- `state.json` with the plan, versions, workload result, diagnostics summary, and artifacts;
- `events.jsonl` with ordered lifecycle events;
- diagnostic and detached-worker logs.

Reports can be inspected or compared without connecting to ClickHouse:

```bash
ch-play inspect-report path/to/report.json
ch-play compare-reports baseline.json candidate.json
```

The comparison explicitly marks reports non-comparable when their content version, report ID,
ClickHouse version, or collection mode differs. Profile hashes, topology, scale, and seed should
also be checked in `state.json`.

## MCP server

Start the stdio server with:

```bash
ch-play-mcp
```

It provides these high-level tools:

- `component_capabilities`
- `validate_experiment`, `plan_experiment`
- `start_experiment`, `run_experiment`
- `experiment_status`, `experiment_events`, `cancel_experiment`
- `teardown_experiment`
- `inspect_diagnostic_report`, `compare_diagnostic_reports`

The server also publishes the experiment, run-state, run-event, and component-contract schemas as
`chplay://` resources.

## Component contract

`ch_play` invokes the three tools through `ch_play/component/v1` machine envelopes. Each component
advertises the hidden interface through:

```bash
ch-stand --machine --request-id probe --component-capabilities
ch-workload --machine --request-id probe --component-capabilities
ch-diag --machine --request-id probe --component-capabilities
```

Every response contains exactly `contract_version`, `component`, `component_version`, `command`,
`request_id`, `status`, `result`, `artifacts`, `warnings`, and `error`.
