PostgreSQL experiment orchestrator
Project description
pg_play
pg_play is the AI-ready orchestration layer for reproducible PostgreSQL
experiments.
- Recreates the same PostgreSQL stand, backend activity, and diagnostic window.
- Applies a versioned
pg_configuratorcandidate only through a reviewedpg_standplan. - Keeps human-facing component CLIs small while exposing a typed MCP workflow to an AI agent.
- Records immutable plan hashes, run state, component versions, and artifact hashes.
- Validates and compares
pg_diagJSON reports without treating a partial collection as a successful complete run. - Plans and runs
pg_perf_benchonly against an explicitly selected disposable database, then validates and compares benchmark artifacts and TPS evidence. - Installs every component while preserving their independent use.
The independently installable components are:
pg_stand— reproducible PostgreSQL stands;pg_workload— profile-driven backend activity emulation;pg_diag— diagnostic JSON and HTML artifacts;pg_configurator— version-aware PostgreSQL configuration candidates.pg_perf_bench— controlled pgbench execution and environment evidence.
How it works
pg_play
|
+-------------+-------------+
| |
v |
pg_configurator |
| versioned config |
v |
pg_stand ------------------------+
|
v
PostgreSQL stand
/ | \
v v v
pg_workload pg_perf_bench pg_diag
| | |
| benchmark report |
+--------- run ----------+----> diagnostic report
|
change one reviewed input
|
+----> rebuild, rerun, compare
The control layers are deliberately separate:
agent skills workflow and interpretation rules
|
v
pg-play-mcp thirteen typed, high-level operations
|
v
pg_play core validation, planning, state, comparison
|
v
component adapters argv arrays + strict JSON envelopes
|
+---- pg_configurator
+---- pg_stand
+---- pg_workload
+---- pg_diag
`---- pg_perf_bench
MCP does not expose arbitrary shell, SQL, Docker, or raw component-command tools. Each component remains pleasant to use directly: orchestration flags are hidden from its primary help and its normal human output is unchanged.
Installation
python -m pip install pg-play
This installs compatible versions of all five component distributions. They remain available through their own commands:
pg-stand --help
pg-workload --help
pg-diag --help
pg-configurator --help
pg-perf-bench --help
Experiment manifest
pg_play/v1 is strict: unknown fields, secret-bearing configurator inputs,
missing projects, invalid profile names, and invalid diagnostic windows are
errors.
api_version: pg_play/v1
kind: PostgreSQLExperiment
metadata:
id: pg18-mixed-baseline
spec:
artifact_root: .pg_play/experiments/pg18-mixed-baseline
stand:
config: ../pg_stand/configs/single.yaml
project: ./stand
configurator:
inputs:
db_cpu: 4
db_ram: 8Gi
pg_version: "18"
db_duty: mixed
workload:
project: ./workload
profiles: [pagila, simple_stock]
scale: 1.0
database: workload_db
user: workload_user
install: true
stop_after_report: true
pgbench_duration_seconds: 30
job_interval_seconds: 5
resource_guard:
disk_max_used_pct: 90
mem_min_available_pct: 10
mem_min_available_mb: 2048
cpu_max_pct: 90
cpu_window_seconds: 60
check_interval: 5
diagnostics:
mode: snapshots
collection_mode: remote-db-only
duration_seconds: 60
interval_seconds: 10
report_name: pg18-mixed-diagnostics
benchmark: # optional
database: pg_perf_bench_test # dedicated and disposable
report_name: pg18-mixed-benchmark
benchmark_type: default
clients: [1, 4, 16] # or times_seconds, never both
init_command: >-
ARG_PGBENCH_PATH -i -s 10 -h ARG_PG_HOST -p ARG_PG_PORT
-U ARG_PG_USER ARG_PG_DATABASE
workload_command: >-
ARG_PGBENCH_PATH -T 60 -c ARG_PGBENCH_CLIENTS -j ARG_PGBENCH_CLIENTS
-h ARG_PG_HOST -p ARG_PG_PORT -U ARG_PG_USER ARG_PG_DATABASE
command_timeout: 120
system_metrics_interval: 1
drop_os_caches: false
collect_pg_logs: true
phases:
benchmark: true
workload_diagnostics: true
recreate_workload_database: true
To use a packaged pg_perf_bench maximum-TPS profile, replace
benchmark_type, init_command, workload_command, and workload_path with:
workload_profile: imdb # imdb or pagila
workload_scale: 1.0
workload_duration_seconds: 30
clients: [1, 2, 4, 8, 16]
The profile supplies its schema, deterministic generator, SQL query set and
command templates. pg_play includes the selected profile and scale in the
reviewed benchmark plan. pg_perf_bench selects the newest local pgbench/psql
pair automatically; optional pgbench_path and psql_path overrides are
accepted only when they are not older than the newest installed clients. The
pg_diag OS sampler runs during every benchmark window; use
system_metrics_interval to control its cadence and
system_metrics_duration only when a custom command has no pgbench -T or
--time option.
Paths are resolved relative to the manifest. spec.stand.project defaults to
the manifest directory and fixes where pg_stand stores state, credentials,
and storage regardless of the caller's current directory. Credentials never
belong in this file. pg_play obtains the stand-owned administrator credential, creates a
random workload credential, and stores project-local passfiles with mode
0600.
The workload resource guard is always enabled by pg_play. Its thresholds are
manifest inputs and therefore part of the reviewed plan hash; override them
only when the host policy is explicitly known.
The packaged JSON Schema is available as the MCP resource
pgplay://experiment-schema.
Shared CLI conventions
pg_diag naming is the reference for equivalent options. Components now use
--host, --port, --database, --user, --password, --out, and
--pg-version wherever those concepts apply. Existing pg_perf_bench --pg-*,
pg_workload --pg-major/--workload-user, pg_stand --postgres-version, and
pg_configurator --output-file-name spellings remain compatibility aliases.
Secrets are the deliberate exception: pg_workload continues to accept
passwords only through environment/passfile mechanisms.
All five components use the same hidden orchestration options:
--machine, --request-id, and --component-capabilities. Their advertised
machine_interface object makes these names machine-verifiable.
Human CLI
The pg-play CLI contains only complete experiment operations:
| Command | Effect |
|---|---|
capabilities |
Read installed component contracts |
validate MANIFEST |
Validate the manifest and non-mutating component inputs |
plan MANIFEST |
Calculate the current read-only plan and its hash |
run MANIFEST --plan-hash HASH --run-id ID |
Execute exactly that plan |
status MANIFEST --run-id ID |
Read durable run state |
inspect-report REPORT.json |
Validate and summarize one diagnostic artifact |
compare-reports BASELINE.json CANDIDATE.json |
Produce deterministic summary deltas |
inspect-benchmark-report REPORT.json |
Validate and summarize one benchmark artifact |
compare-benchmark-reports BASELINE.json CANDIDATE.json |
Check server, environment and methodology identity, then produce TPS deltas |
benchmark-profiles |
List packaged maximum-TPS workload profiles |
benchmark-join-tasks |
List documented benchmark JOIN scenarios |
join-benchmark-reports --report ... --join-task TASK --out DIR --report-name NAME |
Join only the explicitly named benchmark reports |
teardown MANIFEST [--clear-stand-data] |
Stop workload processes and remove the managed stand |
Typical flow:
mkdir -p stand workload
pg-workload init --directory workload
pg-play validate experiment.yaml
pg-play plan experiment.yaml > plan.json
# Copy plan_hash from the reviewed plan.
pg-play run experiment.yaml \
--plan-hash sha256:... \
--run-id baseline-001
pg-play status experiment.yaml --run-id baseline-001
pg-play inspect-report .pg_play/experiments/pg18-mixed-baseline/baseline-001/report.json
run recalculates the plan and rejects a stale hash. A run id is immutable;
retry a changed or failed experiment under a new id.
MCP server
Start the stdio server with:
pg-play-mcp
Configure an MCP client to launch that executable with no shell wrapper. The server exposes only:
component_capabilitiesvalidate_experimentplan_experimentrun_experimentexperiment_statusinspect_diagnostic_reportcompare_diagnostic_reportsinspect_benchmark_reportcompare_benchmark_reportsbenchmark_profilesbenchmark_join_tasksjoin_benchmark_reportsteardown_experiment
An agent should validate, plan, show the mutation to the user, and then call
run_experiment with the unchanged hash and a new run id. The implementation
uses the stable MCP Python SDK
1.x line and intentionally excludes the 2.x prerelease API.
Agent skills
The wheel contains two optional workflow skills under pg_play/skills/:
run-postgres-experiment— validate, plan, execute, and recover a run;analyze-postgres-experiment— inspect reports, compare controlled runs, and design the next single-variable iteration.
Skills contain procedural guidance; they do not reimplement orchestration or invoke raw component commands. Skill registration is agent-runtime-specific, so installing a Python wheel does not automatically activate them in every agent product.
Determinism and safety
- Every component returns the exact
pg_play/component/v1envelope in hidden machine mode and advertisespg_play/capabilities/v1through the common--component-capabilitiesflag. - Plans hash normalized configuration, workload profile contents, scheduler state, and current stand state.
- Parameters owned by stand topology, TLS, fixed CSV logging, or diagnostic
preloads remain under
pg_stand; the plan records those candidate values separately and passes only non-owned parameters topg_stand. - Managed TLS stands are rejected during validation in
pg_play/v1: the component contract does not yet provision a client certificate for the dedicated workload role. Direct TLS use of each component remains available. pg_stand applyverifies its component plan hash;pg_play runverifies the combined plan hash. Machine-modepg_perf_bench benchmarkindependently verifies a content-sensitive benchmark plan hash before resetting its database.- Subprocesses receive argument arrays with
shell=False. - Password-bearing CLI arguments and password-bearing machine output are rejected.
- Background workload stop verifies PID ownership before signaling a process.
- A failed cleanup cannot hide the original collection failure; a cleanup failure after successful diagnostics marks the run partial.
pg_diagpartial artifacts are retained and explicitly marked partial.pg_playnever automatically destroys a stand.
Remote OS collection uses strict SSH host verification. For a newly created
local pg_stand, pg_play captures its host key into the run directory before
starting pg_diag; the captured file is permission-restricted and retained as
run evidence.
Current scope
The first contract covers one configuration candidate, one managed stand, an optional controlled benchmark, selected workload profiles, a one-shot or snapshots report, and deterministic diagnostic and benchmark comparison. Automatic extraction of OS facts and generation or application of TuneD/systemd artifacts remains a roadmap item; it is not silently approximated by the current implementation.
Development
python3 -m venv .venv
.venv/bin/pip install -e ../pg_stand -e ../pg_workload -e ../pg_diag \
-e ../pg_configurator -e ../pg_perf_bench
.venv/bin/pip install -e '.[dev]'
.venv/bin/ruff check .
.venv/bin/ruff format --check .
.venv/bin/pytest
For coordinated releases, publish the component distributions before tagging
pg_play: first pg_configurator, pg_diag, pg_stand, and pg_workload,
then pg_perf_bench (which depends on pg_diag), and finally pg_play.
Ordinary branch CI checks out the component sources so a coordinated source
change can be tested before those versions reach PyPI. Tagged publish jobs use
the package index deliberately and therefore enforce this release order.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pg_play-0.2.0.tar.gz.
File metadata
- Download URL: pg_play-0.2.0.tar.gz
- Upload date:
- Size: 45.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f248e1dad912c2dd80d8d181df52bef94a19844646e1d500f471ebd6235ea0d4
|
|
| MD5 |
46bcdc66ee0e0363d97282d93080795c
|
|
| BLAKE2b-256 |
1c45044f381836102ef94f4f6b4cea601ecced8a76f177c838b0bdbb77b07607
|
Provenance
The following attestation bundles were made for pg_play-0.2.0.tar.gz:
Publisher:
publish.yml on O2eg/pg_play
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pg_play-0.2.0.tar.gz -
Subject digest:
f248e1dad912c2dd80d8d181df52bef94a19844646e1d500f471ebd6235ea0d4 - Sigstore transparency entry: 2219863084
- Sigstore integration time:
-
Permalink:
O2eg/pg_play@e237687a889da6852d8bc84aee61542000d7669a -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/O2eg
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e237687a889da6852d8bc84aee61542000d7669a -
Trigger Event:
push
-
Statement type:
File details
Details for the file pg_play-0.2.0-py3-none-any.whl.
File metadata
- Download URL: pg_play-0.2.0-py3-none-any.whl
- Upload date:
- Size: 38.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d3727e721d3b47da65ed8c13e50712643a9ae672809e3ab5ec87d107a06c0b6c
|
|
| MD5 |
f79fd356d65907e5b5ca6247cdfd8b95
|
|
| BLAKE2b-256 |
2c9c32bd59b67d8dbdba593cbee44d5e8ef1d86c8776af3b23d8cfba682e9f83
|
Provenance
The following attestation bundles were made for pg_play-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on O2eg/pg_play
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pg_play-0.2.0-py3-none-any.whl -
Subject digest:
d3727e721d3b47da65ed8c13e50712643a9ae672809e3ab5ec87d107a06c0b6c - Sigstore transparency entry: 2219863102
- Sigstore integration time:
-
Permalink:
O2eg/pg_play@e237687a889da6852d8bc84aee61542000d7669a -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/O2eg
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e237687a889da6852d8bc84aee61542000d7669a -
Trigger Event:
push
-
Statement type: