pg-play is the AI-ready orchestration layer for reproducible PostgreSQL
experiments.
The distribution and primary installed command are pg-play; the MCP command
is pg-play-mcp. The import package and GitHub repository are named pg_play.
- 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, durable run state, append-only events, 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. - Plans and runs reviewed
pg_converterpackets against an exact alias set through a detached, auditable, sequential workflow. - Installs all eight component distributions while preserving their independent use.
- Optionally builds PostgreSQL through pg_maker, records package/image provenance, and runs the resulting immutable image in pg_stand. See the maker workflow and interface contract.
- Optionally orchestrates logical migration experiments with
pg-logical-repl: durable controllers, DDL delivery, paired diagnostics, independent verification, planned recovery and cutover. See the logical integration guide.
The eight independently installable components are listed below. Distribution
and CLI names use hyphens; Python packages, repository names and component IDs
use underscores (for example, pg-maker and pg_maker).
| Component | Role | Installation with pg-play |
|---|---|---|
| pg-stand | PostgreSQL containers, topology, storage and credentials | Core |
| pg-workload | Datasets and scheduled backend activity | Core |
| pg-diag | Database/OS diagnostics and JSON/HTML reports | Core |
| pg-configurator | Version-aware PostgreSQL configuration candidates | Core |
| pg-converter | Reviewed SQL/Python packets against selected database aliases | Core |
| pg-perf-bench | Controlled pgbench measurements and benchmark comparisons | Core |
| pg-maker | PostgreSQL builds, extensions, patches, package evidence and publication | Core |
| pg-logical-repl | Native logical replication, supported DDL delivery, verification and migration recovery | Core |
- User scenarios: tasks, component flows and ASCII diagrams.
- Maker integration: builds, runtime images and publication.
- Logical replication integration: copy, DDL, verification and recovery.
- Converter integration: reviewed packet execution.
- Agent client setup: MCP and the six packaged skills.
- Changelog: release history; 0.6.0 is currently unreleased.
pg-play: plan -> run -> evidence
|
+-------------+-------------+
| |
pg-maker pg-configurator
packages/image settings
| |
+--------> pg-stand <-------+
|
v
pg-converter ---> PostgreSQL <--- pg-workload
^
+----------> pg-perf-bench
|
+----------> pg-diag -> JSON / HTML
|
source DB == pg-logical-repl ==> target DB
copy + DML +
supported DDL
These are available workflows, not one unconditional pipeline. A standard experiment runs the optional benchmark before workload diagnostics. Converter packets and logical migrations have separate reviewed plans. Live diagnostics and configuration review can use existing servers without pg-stand.
The control layers are deliberately separate:
agent skills workflow and interpretation rules
|
v
pg-play-mcp typed, high-level operations
|
v
pg_play core validation, planning, state, comparison
|
v
component adapters argv arrays + strict JSON envelopes
|
+---- pg_configurator
+---- pg_converter
+---- pg_maker
+---- pg_logical_repl
+---- pg_stand
+---- pg_workload
+---- pg_diag
`---- pg_perf_bench
MCP exposes typed workflow operations. The maker_dev_exec tool runs
an argument vector inside a private copy of a pg_maker build container; it does
not provide a host shell or a database SQL console. Component CLIs remain
independently usable. The logical adapter explicitly selects
--contract pg_play/component/v2; native pg-logical-repl machine output has a
different contract.
Use Linux and Python 3.11 or newer. Managed stands and maker builds need Docker
Engine access; stand credential generation also needs OpenSSL and ssh-keygen.
Benchmark/workload execution needs PostgreSQL client tools on the runner host.
Logical migration requires psql, pg_dump and pg_restore matching the
source/target major. Remote OS diagnostics need SSH access and verified host
keys. Python installation does not provision these system dependencies.
python -m pip install pg-playStarting with pg-play 0.6.0, this installs all eight component distributions. The minimum versions are:
| Distribution | Required version |
|---|---|
| pg-configurator | >=0.11.1,<1 |
| pg-converter | >=2.0b2,<3 |
| pg-diag | >=0.19.1,<1 |
| pg-logical-repl | >=0.2.0,<0.3 |
| pg-maker | >=0.6.0,<1 |
| pg-perf-bench | >=0.7.4,<1 |
| pg-stand | >=0.3.0,<1 |
| pg-workload | >=0.6.1,<1 |
The wheel and source distribution include the README, changelog, public guides
and example configurations. Installed documents retain their relative layout
under share/doc/pg-play. Locate them in the active environment with:
python -c 'import sysconfig; print(sysconfig.get_path("data") + "/share/doc/pg-play")'Each component remains a separate Python distribution with its own CLI and
release cycle. It can be installed independently, for example
python -m pip install pg-stand or python -m pip install pg-logical-repl.
Components do not depend on the pg-play orchestrator; their own dependencies
still apply, such as pg-perf-bench using pg-diag.
Newer compatible versions are allowed. To update an existing installation and its components together:
python -m pip install --upgrade --upgrade-strategy eager pg-play
pg-play capabilitiesMaker and logical replication are required dependencies; installation extras
for those components are not provided. Workflows still check component
capabilities before execution. Maker runtime preflight requires runtime check,
included in the required 0.6.0 release. See the
maker integration guide,
logical integration guide and
changelog.
The components remain available through their own commands:
pg-stand --help
pg-workload --help
pg-diag --help
pg-configurator --help
pg-converter --help
pg-perf-bench --help
pg-maker --help
pg-logical-repl --helppg_play/v1 is strict: unknown fields, secret-bearing configurator inputs,
missing projects, invalid profile names, and invalid diagnostic windows are
errors.
Initialize stand and workload as shown in the CLI flow below, and save this
example as experiment.yaml in their parent directory. Its CPU/RAM values match
the bundled PG18 single-node profile (1 CPU, 1 GiB). When changing stand resources
or the PostgreSQL major, update the configurator inputs to match. This is a small
laboratory example; the workload guard checks the host's available resources.
api_version: pg_play/v1
kind: PostgreSQLExperiment
metadata:
id: pg18-mixed-baseline
spec:
artifact_root: .pg_play/experiments/pg18-mixed-baseline
stand:
config: ./stand/configs/single.yaml
project: ./stand
# Optional values applied after pg_configurator recommendations:
# parameter_overrides:
# auto_explain.log_min_duration: 0ms
# auto_explain.log_format: json
configurator:
inputs:
db_cpu: 1
db_ram: 1Gi
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
# log_depth_time_min: 15 # optional: parse server csvlog for the
# last N minutes (0-1440); needs
# collection_mode local or remote, since
# remote-db-only never reaches the log dir
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: 5
drop_os_caches: false
collect_pg_logs: true
phases:
benchmark: true
workload_diagnostics: true
recreate_workload_database: trueTo 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 on the benchmark runner host during every benchmark
window. Set system_metrics_interval: 5 explicitly for compatibility with the
minimum supported pg-perf-bench release, which rejects shorter intervals;
pg-play's current implicit default is still 1 second. Use
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.
spec.stand.parameter_overrides replaces selected generated PostgreSQL values.
Use it for an experiment that needs specific logging thresholds or connection
limits. Overrides pass the same validation as pg_stand parameters: topology,
TLS, fixed CSV paths and preloaded libraries remain stand-managed. The effective
values and explicit overrides are included in the reviewed plan and its hash;
the configurator artifact hash identifies the original generated candidate.
Configurator safety budgets describe that candidate before manual overrides.
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.
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 eight component adapters use the common orchestration options:
--machine, --request-id, and --component-capabilities. Their advertised
machine_interface object makes these names machine-verifiable. The logical
adapter also supplies the contract selection described above.
The pg-play CLI exposes experiment operations and separate maker, converter
and logical workflows. Live-server capture and configuration review are exposed
through MCP and PgPlayService, not dedicated CLI subcommands.
| Command | Effect |
|---|---|
capabilities |
Read installed component contracts |
maker ... |
Build, inspect, develop, export and publish through the maker adapter |
logical ... |
Plan and monitor logical migration operations and experiments |
plan-converter-run --project DIR --config FILE --packet NAME |
Resolve packet content and exact database aliases without connecting |
start-converter-run PLAN.json --plan-hash HASH --out DIR --run-id ID |
Start an unchanged packet plan in a detached worker |
converter-run-status RUN_DIR |
Read durable packet-run state and detect a lost worker |
converter-run-events RUN_DIR [--after-sequence N] |
Read ordered packet-run events |
cancel-converter-run RUN_DIR [--reason TEXT] |
Request cooperative packet cancellation |
validate MANIFEST |
Validate the manifest and non-mutating component inputs |
plan MANIFEST |
Calculate the current read-only plan and its hash |
start MANIFEST --plan-hash HASH --run-id ID |
Start exactly that plan in a detached worker and return immediately |
status MANIFEST --run-id ID |
Read durable state and detect a lost worker |
events MANIFEST --run-id ID [--after-sequence N] |
Read ordered durable events, with cursor pagination |
cancel MANIFEST --run-id ID [--reason TEXT] |
Request cooperative cancellation |
resume MANIFEST --plan-hash HASH --run-id ID |
Verify and resume a failed, cancelled, or interrupted attempt |
run MANIFEST --plan-hash HASH --run-id ID |
Execute synchronously for compatibility |
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-stand init --directory stand
pg-workload init --directory workload
pg-play validate experiment.yaml
pg-play plan experiment.yaml > plan.json
# Copy plan_hash from the reviewed plan. This command returns after spawning
# the durable worker; it does not wait for the experiment to finish.
pg-play start experiment.yaml \
--plan-hash sha256:... \
--run-id baseline-001
pg-play status experiment.yaml --run-id baseline-001
pg-play events experiment.yaml --run-id baseline-001 --after-sequence 0
# After the run reaches succeeded or partial, inspect its diagnostic artifact:
pg-play inspect-report .pg_play/experiments/pg18-mixed-baseline/baseline-001/pg18-mixed-diagnostics.jsonstart recalculates the plan and rejects a stale hash. A run_id remains
permanently bound to the same manifest and plan. Use resume with that same id
for a verified failed, cancelled, or interrupted attempt; use a new id when the
manifest or plan changes. run retains the old synchronous behavior for
scripts that explicitly need it. Plan/start are separate calls: do not start if
validation fails or the plan is blocked. Hashes such as sha256:... in examples
are placeholders for the full hash returned by the corresponding planner.
CLI operations print JSON on success. Exit code 0 means the request completed; a status request can still return a failed, blocked or interrupted run. Inspect the returned state and evidence, not just the process exit code. Caught input or operation errors print to stderr and return 2.
Teardown is explicit. Wait for active experiments to finish or cancel them first,
then use pg-play teardown experiment.yaml. It stops the workload and removes
the selected stand containers while retaining database storage. Add
--clear-stand-data only to discard that stand's data. Keep run artifacts and
project credentials for inspection or recovery.
pg_converter packets are trusted deployment code and are intentionally
separate from the general experiment manifest. Plan an exact packet, review
its legacy tracker checksum, SHA-256 source-tree hash, Python-step flag, and
resolved database aliases and password-free connection identities, then start
the unchanged plan:
pg-play plan-converter-run \
--project /opt/pg_converter/current \
--config /etc/pg_converter/pg_converter.conf \
--packet release_42 \
--database-selector 'prod_a,prod_b' \
--placeholders-file /run/pg_converter/release_42.json \
--timeout-seconds 3600 > converter-plan.json
pg-play start-converter-run converter-plan.json \
--plan-hash sha256:... \
--out /var/lib/pg_play/converter-runs \
--run-id release-42The machine path always uses sequential database processing and never enables
--force, --wipe, --stop, --unlock, template copying, or skip-on-cancel
modes. The reviewed plan replaces only the interactive multi-database prompt;
it does not bypass PG Converter checksum or ambiguous-outcome safeguards.
Credentials stay in the protected configuration file. Placeholder and
configuration-override values are accepted only through protected JSON files
and are represented in the plan by names and hashes, not values.
See the
pg_converter integration runbook
for the durable directory, cancellation, and recovery contracts.
Start the stdio server with:
pg-play-mcpConfigure an MCP client to launch that executable with no shell wrapper. See Agent client setup for Codex CLI, Claude Code, Hermes Agent, Kimi Code CLI, Gemini CLI and OpenCode.
The server registers the following tools. Optional tools are registered even when their component is absent; install the corresponding extra before use.
| Workflow | MCP tools |
|---|---|
| Component discovery | component_capabilities |
| Experiments | validate_experiment, plan_experiment, start_experiment, run_experiment, experiment_status, experiment_events, cancel_experiment, resume_experiment, teardown_experiment |
| Reports and benchmarks | inspect_diagnostic_report, compare_diagnostic_reports, inspect_benchmark_report, compare_benchmark_reports, benchmark_profiles, benchmark_join_tasks, join_benchmark_reports |
| Live diagnostics | plan_live_diagnostics, start_live_diagnostics, live_diagnostics_status, live_diagnostics_events, cancel_live_diagnostics |
| Configuration review | plan_configuration_review, collect_configuration_facts, generate_configuration_candidate, compare_configuration_candidate |
| Converter packets | plan_converter_run, start_converter_run, converter_run_status, converter_run_events, cancel_converter_run |
| Logical replication | logical_inspect, logical_plan, logical_start, logical_status, logical_events, logical_stop_controller, logical_resume_controller, logical_report |
| Maker builds and runtime | maker_validate, maker_init, maker_config_show, maker_package_names, maker_prepare, maker_resolve, maker_plan, maker_start, maker_status, maker_events, maker_cancel, maker_resume, maker_artifacts, maker_export, maker_runtime_check, maker_runtime_plan, maker_runtime_start |
| Maker development | maker_dev_open, maker_dev_status, maker_dev_patch, maker_dev_build, maker_dev_explain, maker_dev_exec, maker_dev_pin, maker_dev_prune, maker_changes_workspace, maker_changes_validate, maker_changes_export |
| Maker extensions and publication | maker_extension_init, maker_extension_prepare, maker_extension_plan, maker_extension_build, maker_publish_plan, maker_publish_run |
An agent should validate, plan, show the mutation to the user, and then call
start_experiment with the unchanged hash and a new run id. It can poll
experiment_status and page through experiment_events without holding one
long MCP request open. The dependency range for the
MCP Python SDK is
mcp>=1.28,<2; the 2.x API is outside the supported dependency range.
The durable schemas are also exposed as pgplay://run-state-schema and
pgplay://run-event-schema. Additional resources are
pgplay://component-contract and pgplay://configuration-facts-schema.
Core experiment schemas do not describe maker-owned operations or logical run
state; use each workflow's integration guide and returned schema identifiers.
For packet deployment, an agent must call plan_converter_run, show the exact
packet/source hashes, target aliases, Python-step risk, and mutation flags to
the user, and pass the unchanged plan and hash to start_converter_run.
Observe it through converter_run_status and converter_run_events. A failed
or interrupted packet is not automatically retried because non-transactional
actions can have an ambiguous outcome.
The wheel contains six optional workflow skills under pg_play/skills/:
run-postgres-experiment— validate, plan, start, and monitor a new run;run-pg-converter-packet— review exact packet sources and targets, start the immutable run, and preserve ambiguous outcomes for operator recovery;recover-postgres-experiment— inspect, cancel, and safely resume an existing durable run;diagnose-live-postgres— capture a bounded, read-only diagnostic window on an existing PostgreSQL host and interpret the validated report;review-postgres-configuration— inspect an existing server with a minimal read-only diagnostic set, generate a candidate, and compare changed settings;analyze-postgres-experiment— inspect reports, compare or join 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.
compare-reports compares diagnostic summary counts and checks artifact/content
identity, server version and collection modes. It does not calculate per-query
performance changes or verify workload, hardware, topology, observation-window
or seed equality. Check those inputs in the run plans and examine the report
items before drawing conclusions.
compare-benchmark-reports checks iteration axes/values, methodology, server
version and environment identity. It reports configuration changes separately
and still returns deltas when comparability.comparable is false. A successful
command alone does not establish a valid comparison. The mean TPS delta is an
aggregate of the reported measurements, not a statistical significance test.
For deliberate configuration, CPU, memory, storage, OS or PostgreSQL-version
changes, select a task from benchmark-join-tasks and use
join-benchmark-reports. JOIN enforces the controls for that task and rejects
incompatible inputs. See the comparison scenario.
plan_live_diagnostics accepts PostgreSQL and SSH access references, one of
the reviewed intents (performance, locks, io, or cpu), and a bounded
snapshots window. It returns missing inputs, the exact versioned item allowlist,
safety limits, and a content hash without connecting to the target. Passwords,
private-key contents, arbitrary SQL, shell commands, tags, and caller-selected
item ids are not accepted.
SSH authentication is selected explicitly in target.ssh. Existing key-path
requests remain valid and are normalized to auth: "key":
{
"ssh": {
"host": "db.example",
"user": "postgres",
"auth": "key",
"key_path": "/secure/path/id_ed25519",
"known_hosts_path": "/secure/path/known_hosts"
}
}To use a key already loaded into a local agent, set auth: "agent" and omit
key_path and key_passphrase_env:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -l{
"ssh": {
"host": "db.example",
"user": "postgres",
"auth": "agent",
"known_hosts_path": "/secure/path/known_hosts"
}
}Agent plans contain only the authentication method, not the ephemeral socket
path. Planning and starting require a live Unix socket in SSH_AUTH_SOCK.
The detached diagnostics worker explicitly inherits that variable and passes
it to pg-diag; the same agent and socket must therefore remain alive until
the capture reaches a terminal state. pg-play never starts an agent, runs
ssh-add, or forwards the agent to the target.
start_live_diagnostics stores the unchanged plan in a new immutable capture
directory and starts a detached worker. The worker invokes pg-diag snapshots
in full remote mode, writes portable JSON and HTML, validates the JSON artifact,
and records ordered events and terminal state. MCP disconnection does not stop
the worker. Use live_diagnostics_status and live_diagnostics_events to
observe it and cancel_live_diagnostics for cooperative cancellation.
Capture duration is limited to 30–900 seconds, interval to 5–60 seconds, and
the schedule to at most 121 snapshots. A lost worker produces interrupted;
the existing evidence is retained and a new time window requires a new capture
id rather than a misleading resume or merge.
pg_play exposes a deliberately read-only review workflow for an existing
PostgreSQL server. plan_configuration_review reports missing database, SSH,
and tuning-intent inputs. collect_configuration_facts runs one bounded
pg-diag one-shot collection containing only server version, effective
pg_settings, database size, CPU, RAM, filesystem, mount, disk, and extension
inventory items. It stores both the original diagnostic report and a compact
pg_diag/configuration-facts-v1 artifact.
generate_configuration_candidate combines those observed facts with the
explicit database duty, storage class, replication mode, and PITR intent. The
result is a pg_configurator/v1 or pg_configurator/v2 candidate; the two
differ in how the candidate reports its own findings, not in the parameter
mappings this workflow reads. Finally,
compare_configuration_candidate writes JSON and Markdown containing only
changed or unobserved parameters, including current source, apply mode,
pending-restart state, calculation rule, and warnings.
The workflow never applies configuration, reloads PostgreSQL, restarts a
service, or treats a candidate as a benchmark-proven optimum. During collection,
pg-diag remote mode opens a bounded dynamic local SSH forward to the requested
PostgreSQL endpoint and closes it with the collection session. Passwords and
private-key contents are not accepted; callers provide a passfile reference,
strict known-hosts path, and either a key-path reference or explicit agent mode.
Each run directory contains state.json, the original experiment.yaml, the
reviewed plan.json, postgresql-parameters.json, append-only events.jsonl,
and worker.log. start_experiment launches a detached worker with its own
session, so closing or crashing the MCP stdio process does not terminate the
experiment. If the worker itself disappears, the next experiment_status
changes an active run to interrupted.
Cancellation is a durable request in cancel.request.json. The worker checks
it before every step and while a component is running. A running component is
started in its own process group; before pg_play signals a process left behind
by a crashed worker, it verifies the recorded PID start time, operating-system
user, and executable identity.
Resume is intentionally conservative:
| Step | Safe resume rule |
|---|---|
| maker (when configured) | Verify the locked plan, reuse completed build/runtime operations, or explicitly resume their native workers |
| stand | Recalculate a read-only pg_stand plan and reconcile only the reviewed desired configuration |
| benchmark | Retry only through pg_perf_bench's idempotent dedicated-database reset |
| prepare database | Retry the declarative database preparation operation |
| install workload | Retry the idempotent profile installation operation |
| start/stop workload | Reconcile the requested running/stopped state |
| diagnostics | Retry the read-only collection operation |
Before a resume, pg_play verifies the manifest hash, plan hash, configuration artifact, installed component versions, the exact allowlisted resume policy for every recorded step, and all recorded artifact paths, sizes, and SHA-256 hashes that are available.
Completed benchmark and diagnostic steps must have report artifacts. A valid completed step is reused; an incomplete step or a step with missing or changed artifacts is rerun only when its operation is in the allowlist above. Any unknown step or changed core artifact blocks recovery.
- Every component returns an exact component envelope in hidden machine mode
and advertises
pg_play/capabilities/v1through the common--component-capabilitiesflag. Two envelope versions are accepted while the components migrate:pg_play/component/v1carrieswarnings, a list of sentences, andpg_play/component/v2carriesadvisories, objects with a stablecode, aseverityofwarning,assumptionorinfo, and thesettingeach one is about. Neither may carry the other's field. Anything read throughenvelope_advisoriesarrives in the v2 shape either way; a v1 sentence becomes awarningwith a nullcode, because that is all v1 can express. - 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.startandresumeenforce the same hash. Machine-modepg-perf-bench benchmarkindependently verifies a content-sensitive benchmark plan hash before resetting its database.pg-converter runindependently verifies the reviewed component plan hash, including the exact alias set, packet source tree, and file-based inputs.- Subprocesses receive argument arrays with
shell=False. - The adapter rejects
--passwordand--show-passwordarguments; workflow validators restrict credential inputs to their supported references. Envelope validation checks structure, not arbitrary secret content. Reports, SQL/log text, component errors and exports may contain sensitive data; review and redact artifacts before sharing them. There is no universal output scrubber. - Detached component cleanup verifies PID start time, process ownership, and executable identity before signaling a process group.
- 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.- Normal experiment completion retains the stand. A reviewed stand action can
recreate containers to apply configuration;
teardownexplicitly removes them and deletes storage only with--clear-stand-data.
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.
The standard pg_play/v1 manifest 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.
Existing-server incident capture is separately limited to the four reviewed
read-only profiles and one bounded snapshots window per immutable capture id.
Configuration review extracts the bounded CPU, RAM, filesystem, mount, and disk
facts listed above. Generation or application of TuneD/systemd artifacts remains
a roadmap item; it is not silently approximated by the current implementation.
Reviewed pg_converter runs are a separate durable workflow and are not
silently injected into every experiment manifest. Optional spec.maker adds a
build/runtime-image phase. Logical migration uses a separate migration YAML and
pg_play/logical-experiment-v1 scenario, with its own worker and recovery model.
It currently supports same-major PostgreSQL 15–18 migrations in a restricted
laboratory profile, not cross-major upgrade qualification.
Independent experiments can select different spec.stand.project directories.
Concurrent stands require pg-stand 0.3.0+ and distinct names, ports, storage and
workload roots. The pg-stand dependency includes support for those features.
See multiple-stand scenarios.
labs/ contains repository-only scenarios that drive real stands through pg-play.
They are tracked in Git and excluded from both the wheel and source distribution.
The site demo lab collects a five-minute report
with ten workload profiles and staged incidents, then anonymizes and audits it.
Its README describes stand/data preparation, current reproduction limits and
historical reference measurements.
Use Python 3.11+ and current component checkouts whose versions satisfy the minimums above. Install the orchestrator and all eight components in one resolver transaction, so unpublished local releases satisfy each other's requirements:
python3.11 -m venv .venv
.venv/bin/python -m pip install \
-e ../pg_configurator -e ../pg_converter -e ../pg_diag \
-e ../pg_logical_repl -e ../pg_maker -e ../pg_perf_bench \
-e ../pg_stand -e ../pg_workload -e '.[dev]'
.venv/bin/ruff check .
.venv/bin/ruff format --check .
.venv/bin/pytest
.venv/bin/python -m pip checkBranch CI checks out all eight component repositories and runs the tests on Python 3.11 and 3.12. It builds a wheel set, installs only pg-play into a clean environment and verifies automatic dependency installation, component identities, versions and capability contracts. It also installs each component in a separate clean environment and verifies that pg-play is absent. The same installation checks run before publication using the component releases available from PyPI. Docker/database integration tests have separate prerequisites; these installation and unit checks do not qualify full database migrations or PostgreSQL builds.
For coordinated releases, publish all required component distributions before tagging pg-play. Publish pg-diag before any pg-perf-bench release that requires it, and publish pg-maker, pg-stand and pg-logical-repl updates before a pg-play release that requires their versions. Ordinary branch CI can exercise coordinated source changes before publication; tagged publishing jobs deliberately resolve components from PyPI and enforce this release order.