Agent skill

Double Check Perf Tests

by ClickHouse in ClickHouse/ClickHouse

Locally reproduce ClickHouse CI performance comparison results for a given commit.

Apache-2.0Auto-check: notesDatabases

Install Double Check Perf Tests

skills CLI
$ npx skills add ClickHouse/ClickHouse --skill double-check-perf-tests -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install ClickHouse/ClickHouse double-check-perf-tests --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/ClickHouse/ClickHouse.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/double-check-perf-tests .claude/skills/double-check-perf-tests && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
double-check-perf-tests
GitHub stars
50k
Token cost
~6.4k tokens
SKILL.md length
3,537 words
Files
2
Skills in repo
24
Repo updated
First seen
Licence
Apache-2.0

At a glance

Locally reproduce ClickHouse CI performance comparison results for a given commit.

  • Works in 4 steps: Sanity checks → Resolve the commit → Run the comparison → …
  • Wants to double-check
  • SKILL.md covers What it does, Arguments, Procedure and Notes, plus 1 more section
  • Runs Python scripts from its folder; calls python3, clickhouse and wget

What it does

Double Check Perf Tests is an agent skill from ClickHouse/ClickHouse. Locally reproduce ClickHouse CI performance comparison results for a given commit. Fetches the perf CI report, identifies queries categorized as "Changes in Performance", downloads both the patched and reference binaries from S3 (matching the current machine architecture), and re-runs only those queries via tests/performance/scripts/perf.py to verify whether each regression/improvement is real. Use this whenever the user wants to "double-check", "reproduce", "verify locally", or "re-run" a perf check result —…

Its SKILL.md is about 6.4k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `double_check_perf.py`).

It sits in Databases, covering Data warehousing and File uploads and storage. It works with ClickHouse. The repository describes itself as: ClickHouse® is a real-time analytics database management system. The licence is Apache-2.0.

When your agent uses it

  • Wants to double-check
  • Re-run a perf check result — even if they dont name the skill

Example prompts

  • “Changes in Performance”
  • “double-check”
  • “reproduce”
  • “/double-check-perf-tests”

Requirements

  • Python 3
  • Pre-approved tools (allowed-tools): Bash, Read, Grep, Glob, WebFetch

Workflow steps

4 steps, taken from the step headings in SKILL.md.

  1. Sanity checks
  2. Resolve the commit
  3. Run the comparison
  4. Present the results

What it can do on your machine

Read from SKILL.md and the folder at commit d741c98. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves these tools, so the agent can use them without asking each time:

    • Bash
    • Read
    • Grep
    • Glob
    • WebFetch

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships script files (Python), which the agent can run.

    Shell commands in SKILL.md call:

    • python3
    • clickhouse
    • wget
    • gh

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use wget and gh, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Double Check Perf Tests loads about 6.4k tokens when it runs. Until then it costs about 144 tokens; SKILL.md has 3,537 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~144
When it runs · the whole SKILL.md, loaded when a task matches
~6.4k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check: notes

The automated check noted patterns worth knowing about, such as sudo or a known installer.

  • NotePre-approves every shell command (allowed-tools: Bash)SKILL.md
    allowed-tools: Bash, Read, Grep, Glob, WebFetch

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from ClickHouse/ClickHouse at commit d741c98, republished under its Apache-2.0 licence (© ClickHouse). 3,537 words, ~6,366 tokens.

Download SKILL.mdSave it as .claude/skills/double-check-perf-tests/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
double-check-perf-tests
description
Locally reproduce ClickHouse CI performance comparison results for a given commit. Fetches the perf CI report, identifies queries categorized as "Changes in Performance", downloads both the patched and reference binaries from S3 (matching the current machine architecture), and re-runs only those queries via `tests/performance/scripts/perf.py` to verify whether each regression/improvement is real. Use this whenever the user wants to "double-check", "reproduce", "verify locally", or "re-run" a perf check result — even if they don't name the skill.
allowed-tools
Bash, Read, Grep, Glob, WebFetch
argument-hint
<commit-sha> [--db-path <path>]

Double-check ClickHouse perf-test results

What it does

Given a commit SHA from a PR that ran the Performance Comparison check, this skill:

  1. Looks up the PR for the commit (via gh api).
  2. Detects the local machine's architecture (amd / arm).
  3. Discards shards CI did not run (SKIPPED, PENDING, RUNNING, DROPPED) — they publish no artifacts, so a synthesized report URL only returns HTTP 403. If no shard ran, the skill stops with an error rather than reporting "no changes": "CI never ran the comparison" and "CI ran it and found nothing" are different answers, and only the second is a verdict. It stops the same way when shards ran but none of their reports can be read (expired artifacts), and when some report is unreadable and the readable ones happened to be clean: a missing report contributes no changed queries, exactly like a shard that had none, so "clean" would be a claim about a part of the comparison nobody looked at. When there are changes to rerun, an unreadable shard instead marks the run INCOMPLETE in the report and makes the exit code non-zero. It also stops when any shard carries a baseline other than master_head — see the release_base limitation below.
  4. For each remaining perf shard, fetches report.html and extracts the rows in the "Changes in Performance" table (<tr id="changes-in-performance.<test>.<idx>">), then pulls the timing numbers for those rows from all-query-metrics.tsv. This matches the report exactly — re-implementing compare.sh's changed_show predicate locally would require historical thresholds and per-test <report_threshold> settings we don't have on the client side.
  5. Runs every CI-flagged query locally — even ones flagged only on a different architecture. Cross-arch changes still get measured against the same two binaries; the report table tags each row with a "CI@" column showing which arch(es) CI flagged the query on (e.g. arm-only means CI saw the change on ARM but the local rerun is on AMD). This surfaces silent drift on the local arch and lets the user judge whether an <arch>-only CI verdict was real or noise. One row per query survives the cross-arch dedup, but each arch's CI numbers are kept: when CI called the same query slower on one arch and faster on the other, a CI split line under the row shows both, since the row itself can only carry one.
  6. Resolves the reference (left/baseline) git SHA used by the CI run by querying query_metrics_v2 on play.clickhouse.com for the row with new_sha = <pr-sha> (the report.html "Tested Commits" section is unreliable — for official builds clickhouse --version does not embed the git hash). The lookup is scoped to the pull request as well as the commit and architecture, so a run of the same commit under a different pr_number cannot supply the baseline. Within that scope, a commit measured more than once has one reference per run, so the newest one is taken — that is the run the S3 report reflects, since it is overwritten in place — and the script warns when the choice was not unique.
  7. Downloads both binaries from clickhouse-builds:
    • Right: PRs/<pr>/<sha>/pr/build_{amd,arm}_release/clickhouse
    • Left: REFs/master/<ref-sha>/masterci/build_{amd,arm}_release/clickhouse
  8. Starts two local clickhouse-server processes (ports 9001 + 19001, the same ports CHServer uses in ci/jobs/performance_tests.py).
  9. Reruns only the affected query indices via tests/performance/scripts/perf.py for each affected XML.
  10. Prints a side-by-side comparison: CI numbers vs. local numbers, with a verdict per query (CONFIRMED slower, NOT REPRODUCED, no local data).

Arguments

  • $0 (required): commit SHA (full or short — gh resolves short hashes).
  • --db-path PATH (optional): directory with the standard perf datasets loaded (hits10, hits100, hits_v1, values, tpch10, tpcds1). Must match the layout of ci/tmp/perf_wd/db0. If omitted, the script probes ci/tmp/perf_wd/db0.
  • --pr N, --reference-sha SHA: override auto-detection.
  • --runs N: minimum measurements per query. Unset by default, as in CI — perf.py's adaptive policy decides the counts from its --min-runs / --tau precision stop. Passing a value only widens that policy and changes the sampling, and with it the medians, the rerun precision and the verdict.
  • --populate: rebuild the affected hits tables on each server separately, the way CI's populate_data_both does, instead of sharing one hardlinked copy. See "Hardlinked data vs. --populate" below.
  • --no-cpu-pinning: don't pin the servers with taskset and don't cap max_threads. Only for a machine where pinning is undesirable — it measures under noisier conditions than the report being checked.
  • --use-working-tree-tests: run this checkout's tests/performance and configs instead of the ones from the commit under test. Only for iterating on a local change to a test — see the note on pinning below.
  • --dry-run: stop after resolving PR / SHAs / changed queries; do not download or run.
  • --port-offset N: shift every port the script uses. The defaults mirror CI, where the left server sits on the standard ClickHouse ports (8123/9009/9181/9234); on a development machine a local server usually owns those and the run is refused. Shifting is the safe fix — never stop someone else's server. Does not affect what is measured.

Procedure

1. Sanity checks
  • --dry-run needs nothing but python3 and git: the query expansion runs perf.py with stand-ins for clickhouse_driver and scipy, which it imports at module scope but never uses on the metadata path. The rerun itself does need them, and is refused up front, before any download, if they are missing.

  • The skill must be invoked from the root of a ClickHouse checkout (the script verifies tests/performance/scripts/perf.py is present).

  • The dry-run inspects only the flagged query indices of every affected XML — asking perf.py --print-queries to expand them, since one <query> element with substitutions becomes several numbered queries — plus every create_query/fill_query/drop_query, which run whatever --queries-to-run says. It prints the list of external datasets they actually reference (hits_*, test_values, tpch.*, tpcds.*). Most perf tests are self-contained — they CREATE TABLE … FROM numbers(…) and need no preloaded data at all. Only require the datasets the changed queries truly use; do not insist on the full 50 GB bootstrap.

  • If the affected XMLs reference zero external datasets, the script creates an empty ci/tmp/perf_wd/db0 automatically and proceeds.

  • If they do reference one or more external datasets and ci/tmp/perf_wd/db0 is missing, the script bails with the minimal list of tarball URLs needed for this particular run. Ask the user before downloading. Example: if the only affected XML uses hits_100m_single, just fetch that one tarball (~10 GB) into ci/tmp/perf_wd/db0, not all six.

    bash
    mkdir -p ci/tmp/perf_wd/db0/data/default
    # extract only the tarballs the dry-run identified as needed
    wget -nv -nd -c "<url-from-dry-run>" -O- | tar --extract -C ci/tmp/perf_wd/db0

    Do not auto-download — confirm with the user first.

2. Resolve the commit

Always run a dry-run first so the user can sanity-check what's about to be rerun before any download starts:

bash
python3 .claude/skills/double-check-perf-tests/double_check_perf.py <commit-sha> --dry-run

This prints: PR number, architecture, reference SHA, and the list of affected XML files with their changed query indices. If anything looks wrong (wrong arch, wrong reference SHA, wrong PR), pass --pr / --reference-sha to override. Resolving the reference SHA needs clickhouse client; on the dry-run path its absence is only a warning and the line reads unresolved, so planning keeps working on a bare checkout. The real run still refuses to start without it.

3. Run the comparison
bash
python3 .claude/skills/double-check-perf-tests/double_check_perf.py <commit-sha>

Working directory defaults to tmp/double_check_perf/ in the cwd (per CLAUDE.md: don't use /tmp). It contains:

  • left/clickhouse, right/clickhouse — downloaded binaries, each with a .identity file recording the SHA it was built from. The work dir is shared across runs, so a cached binary is reused only when it is the one the current invocation asked for; a different commit or --reference-sha re-downloads.
  • left/db/, right/db/ — hardlinked dataset copies
  • left/server.log, right/server.log — server logs
  • raw/<test>-raw.tsv — perf.py output per test
  • result.json — structured result of the local rerun
4. Present the results

The script prints a table. For each changed query show:

  • CI old / new / Δ (from the report)
  • Local old / new / Δ / p-value (from perf.py)
  • Verdict: CONFIRMED slower|faster, NOT REPRODUCED, no local data, NO VERDICT (CI's threshold for a demoted query is unavailable), query ERRORED locally ... NOT MEASURED, or perf.py FAILED ... NOT MEASURED. The last two are not verdicts about the change: nothing was measured, and raw/<test>-err.log says why. Either one also makes the script exit non-zero. ERRORED is the sneaky case — perf.py drops a query that failed on every server (if len(no_errors) == 0: continue) and still exits 0, writing only a traceback to stderr, so without reading that log it would look like the benign no local data. Any stderr from an otherwise-clean perf.py run is taken as that signal.

A query counts as CONFIRMED when the local rerun passes the same gate compare.sh uses to confirm a flagged query: same direction, |Δ| above the per-query threshold CI used to flag it, and |Δ| >= stat_threshold of the rerun itself (non-strict, as in compare.sh). Anything else is NOT REPRODUCED, and the verdict says which of the three conditions failed.

A query CI flagged and then demoted in its own confirmation rerun is kept and marked * in the CI@ column. compare.sh retracts such queries from all-query-metrics.tsv while still listing them in the report, so their numbers are read from report.html instead — dropping them would turn a non-empty CI report into an all-clear, and they are exactly the ambiguous results a local rerun should settle. A flagged query readable from neither source is reported as unresolved, and if that leaves nothing to rerun the skill fails rather than calling the comparison clean.

Retracting a demoted query from the TSV also takes its changed_threshold with it, and judging it by the bare 0.15 floor would be a weaker gate than the one CI used — enough to call a historically noisy query CONFIRMED. The threshold is therefore rebuilt the way compare.sh builds it, ceil(greatest(0.15, historical p99 x 1.5, the test's max_ignored_relative_change), 2), running CI's own historical-thresholds query against play.clickhouse.com with the window anchored on the day that run happened rather than today, and keyed by (test, query_index, query_display_name) — the join compare.sh performs, with the display name derived from the pinned test tree via perf.py --print-queries rather than scraped from the report (report.py writes query text into the table cell unescaped, so a query containing < and > cannot be recovered from the HTML). The historical rows come back as JSONEachRow, not TSV: most display names are multi-line — query_display joins statements with ;\n and keeps the XML body's own newlines — and TSV output re-escapes those, so a TSV-keyed lookup would miss every multi-line query and silently drop it to the floor — so an edited query body at the same positional index falls back to the floor instead of inheriting the learned threshold of the query that used to be there. This applies only to rows read from report.html; a shard old enough to predate the changed_threshold column keeps the documented 0.15 floor, since CI exported no threshold for it either. If it cannot be recovered the query is reported with no verdict instead of being judged under a weaker rule.

stat_threshold is the q99 of the balanced-split null — the measurement precision this rerun actually reached. It is recomputed from the rerun's own per-run samples (the query rows of the raw TSV, the same lines compare.sh collects for its confirmation step), using perf.py's own stat_threshold function, lifted out of the script rather than reimplemented so the two cannot drift. perf.py's p-value is displayed but does not decide anything: it is a Welch t-test, not the statistic the CI gate applies.

The threshold is not a fixed number: compare.sh computes it per query as the 0.15 floor raised by the query's historical p99 and the test's <max_ignored_relative_change>, and exports it as the changed_threshold column of all-query-metrics.tsv. A historically noisy query therefore has to clear a much larger bar than a stable one. Using a flat bar instead would let the rerun call a change CONFIRMED that CI's own gate would not have flagged — the floor alone is deliberately above the 10–15% that micro benchmarks swing between two binaries from machine noise and code layout. Shards predating the column fall back to the 0.15 floor.

When summarising back to the user, separate the confirmed regressions / improvements from the not-reproduced cases. Confirmed regressions are the ones worth investigating further; not-reproduced ones can usually be treated as CI noise.

Show full SKILL.md (1,562 more words)Show less

Notes

  • The same tests/performance/scripts/perf.py and the same drop-in config files (tests/performance/scripts/config/{config.d,users.d}) are used as in CI, so the run is as close to CI as possible without Praktika. The ports and shared dataset directory match CHServer in ci/jobs/performance_tests.py.
  • The tests come from the commit under test, not from your checkout. tests/performance (the XMLs, perf.py, the perf config drop-ins), tests/benchmarks (the SQL and settings tpch.xml / tpcds.xml / tpch-join_algorithm-* load through file="..."), programs/server and tests/config/top_level_domains are extracted from the commit CI measured into tmp/double_check_perf/perf-tree/<sha> and everything runs from there, fetching the commit if the clone lacks it — and if the clone's .git cannot be written to, as in some sandboxes, into a scratch repository under the work dir instead. Only this checkout's own origin is fetched into the clone; the scratch repository additionally tries the canonical upstream with --depth=1, so a fork checkout — whose refs/pull/<n>/head is a different pull request — still resolves the commit. A fetch counts only when the commit is present afterwards, never on the fetch's exit code. This is not a nicety: query indices are positional and substitutions expand them, so an XML that gained or lost a query means index n is a different query — on a checkout of this repo one commit behind, and_compare_chain_derived.xml has no query #2 at all while CI flagged exactly that. A refs/pull/<n>/merge checkout has the same problem, since it is not the commit CI measured. perf.py and the thresholds it computes are pinned for the same reason.
  • CPU pinning. On Linux x86_64, CI pins both servers with taskset to one hyperthread per physical core and caps max_threads at the size of that set, so query threads never share a hyperthread sibling depending on scheduler mood — CI's top suspect for the amd-vs-arm A/A noise gap (0.51% vs 0.42%). The script does the same, including the same --jemalloc_profiler_sampling_rate. This matters for the verdicts: an unpinned rerun is noisier than the report it is adjudicating, which is how a real change ends up looking NOT REPRODUCED. arm runs on real cores and is not pinned, in CI or here.
  • The reference (left) binary's git hash is resolved via play.clickhouse.com (anonymous explorer user, no credentials needed), using the query_metrics_v2.old_sha column for the matching new_sha and arch. If that query fails or returns nothing (e.g. the run never finished uploading), pass --reference-sha explicitly. The CI sets this field from SELECT value FROM system.build_options WHERE name='GIT_HASH' on the reference binary itself, so the resulting SHA is guaranteed to match a buildable commit under REFs/master/<sha>/masterci/build_*_release/.
  • Datasets are intentionally not downloaded automatically — they are large and the user should opt in. Existing data is hardlinked into both server dirs via cp -al (same trick performance_tests.py uses), so disk usage stays low.
  • The perf framework expects test.hits (not datasets.hits_v1) for several tests (url_hits, count_from_formats, ...). By default the script runs a temporary "preconfig" clickhouse-server pointed at db0 and issues CREATE DATABASE test; RENAME TABLE datasets.hits_v1 TO test.hits via SQL, so one copy of the data is shared by both sides. (ci/jobs/performance_tests.py instead builds test.hits with INSERT SELECT on each server — that is what --populate reproduces, and under --populate this rename is skipped so the source table stays available to both sides.) Doing this via filesystem-only moves of the .sql files looks equivalent but leaves bookkeeping in a state that crashes the next server start while loading tpcds (NULL deref in DatabaseOrdinary::getConvertToReplicatedFlagPath). Always use the SQL path. Step is idempotent — skipped if test.hits already exists in db0. After the preconfig server exits, the script strips data/system, metadata/system, status, preprocessed_configs from db0 since those are per-server state that mustn't be shared between the left/right hardlinked copies.
  • Hardlinked data vs. --populate. By default both servers read one hardlinked copy of db0 (cp -al, the same trick performance_tests.py uses), so the parts they read were written by whatever binary produced the dataset tarball. CI does not do this: its populate_data_both re-inserts hits_10m_single, hits_100m_single and datasets.hits_v1 → test.hits on each server, so each side's parts carry that side's own write-time defaults (sparse columns, statistics, mark format). A regression that lives in the write path, or one that only shows on freshly written serialization, therefore comes back NOT REPRODUCED under the default. Pass --populate to reproduce CI faithfully; it only rebuilds the hits tables the affected XMLs actually reference, but each one is a full rewrite per side (hits_100m_single alone is ~21 GiB and tens of minutes) and gives up the hardlink disk saving for those tables. When a confirmed CI regression does not reproduce and the PR touches anything on the write path, rerun with --populate before calling it noise.
  • Between test XMLs, everything a test wrote into user_files is removed from both sides while the seeded fixture symlinks are kept — the same cleanup CI runs after every test. Tests write there with INSERT INTO FUNCTION file(...) (parquet_read, json_type_parsing, insert_values_with_expressions, ...) and drop_query only drops tables, so without it a later XML can read what an earlier one left behind and a multi-test rerun becomes order-dependent.
  • --profile-seconds 0 is a deliberate deviation: CI passes 10. The profile runs happen after a query's diff has been computed, so they cannot change its numbers, and this skill does not collect flamegraphs.
  • The skill does not attempt to reproduce flamegraphs or profiling — for that, use the perf-report skill on the same PR.
  • Architecture mismatch is not a blocker. The script runs queries flagged on either arch locally, and that rule keeps applying when the local arch has no shards at all — an ARM-only report is the common case, since the AMD shards run only for a PR labeled pr-performance. Only the play.clickhouse.com lookups are keyed by architecture, so they ask about an arch CI measured; what they return is a master commit, and every master build publishes both arches, so the local-arch binaries for it exist regardless. When CI never measured the local arch the script says so up front and again under the table: the CI old/new/Δ columns are then the other arch's timings, so NOT REPRODUCED means "the local arch does not show it", not "CI was wrong". For the strictest verification, run the skill on each arch separately; otherwise the AMD rerun of an ARM-only change is still useful ("local AMD doesn't reproduce the ARM regression" is a meaningful and common verdict).
  • Only the master_head baseline is supported. CI runs a second flavour of the comparison, release_base, which measures against the latest release build and checks out that release's tests/performance before running. Nothing in this skill is baseline-aware: the left binary is always fetched from REFs/master/<ref-sha>/, query indices are positional in the tests tree of the commit under test, and the reference-SHA lookup cannot discriminate either, because the query_metrics_v2 table exposed on play.clickhouse.com has no baseline_kind column to filter on. Rows from the two baselines share the same (test, query_index) key, so merging them would adjudicate release-baseline queries against a binary and a query numbering CI never used. The script refuses such a report instead. In practice this is unreachable today — only the master workflow schedules release_base (ARM only), and its reports live under REFs/, which this skill does not read — so the check is a guard against that changing.
  • The work dir is reused, so Keeper state is wiped on every run. tmp/double_check_perf persists between invocations (that is what makes the binary cache worth having), but the embedded Keeper's coordination directories are only valid for the data they were written against. The db copies are recreated from db0 each run, so the coordination dirs are removed alongside them — left/coordination, right/coordination and the preconfig server's coordination0. Without that, alter_select.xml, the one perf test that creates a ReplicatedMergeTree('/tables/{database}', '{table}'), hits REPLICA_ALREADY_EXISTS on its create_query against the previous run's znodes and the whole test goes unmeasured.
  • Some shards upload all-query-metrics.tsv.zst (zstd-compressed) instead of plain .tsv — the script detects the URL suffix and decompresses on the fly (uses the zstandard Python package if available, else shells out to zstd -dc).
  • Wait for merges before measuring on freshly-loaded data. A dataset tarball drops parts at whatever merge level the snapshot was taken; ClickHouse queues consolidation merges on startup. While those run the number of parts drifts (changes plans, prefetch, external-storage cache reuse) and the merge threads themselves compete for CPU/IO with the queries being timed. The signal we look for is no new merge scheduled: the script polls SELECT min(elapsed) FROM system.merges on both servers and considers them settled once the youngest in-flight merge has been running for at least 2 minutes (so nothing new has started in that window). This is more useful than waiting for count()=0: long-running merges can stretch that wait by tens of minutes for no real gain once the rate of new merges has dropped to zero. Pass --skip-wait-for-merges only when reusing a perf working directory that already settled in a previous run.

Rules

  • Always run --dry-run first and show the user the plan before downloads.
  • When datasets are missing, ask the user before bootstrapping. Don't silently fire off multi-GB downloads.
  • Don't truncate or summarize the result table — every changed query must be visible, same principle as the perf-report skill.
  • If the script reports NOT REPRODUCED for a query that has a large CI delta, suggest re-running with --runs 13 (more samples) before declaring it flaky. If the PR changes anything that affects how parts are written, suggest --populate too — the default hardlinked dataset cannot show a write-path change at all.

© ClickHouse, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 1 other file in .claude/skills/double-check-perf-tests of ClickHouse/ClickHouse.

  • SKILL.md
  • double_check_perf.py

Open the folder on GitHubat commit d741c98

Compare with similar skills

Double Check Perf Tests next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Double Check Perf Tests compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Double Check Perf Tests this skillClickHouse/ClickHouse50k—~6.4kAutomated safety check: NotesApache-2.0
Chdb SQLvemetric/vemetric3951 repos~1.2kAutomated safety check: PassApache-2.0
Debugging Signals PipelinePostHog/posthog40k—~2.4kAutomated safety check: NotesCustom licence
Clickhouse Architecture Advisorvemetric/vemetric3952 repos~791Automated safety check: PassApache-2.0
Clickhouse Ioaffaan-m/ECC276k3 repos~2.3kAutomated safety check: PassMIT
Clickhouse Ioaffaan-m/ECC276k2 repos~2.3kAutomated safety check: PassMIT

Similar skills

  • Chdb SQL

    vemetric/vemetric

    A skill your agent uses when the user wants to run SQL — especially analytical SQL — on local files (parquet/csv/json), URLs, S3 paths, or remote databases (Postgres, MySQL, MongoDB, ClickHouse…

    395 GitHub starsUsed in 1 repo~1.2k tokens
    DatabasesAuto-check passed
  • Official

    Debug the signals pipeline locally end-to-end. An agent skill from PostHog/posthog.

    40k GitHub stars~2.4k tokensUpdated yesterday
    AI & LLM EngineeringAuto-check: notes
  • MUST USE when designing ClickHouse architectures, selecting between ingestion or modeling patterns, or translating best practices into workload-specific system designs.

    395 GitHub starsUsed in 2 repos~791 tokens
    DatabasesAuto-check passed
  • Clickhouse Io

    affaan-m/ECC

    ClickHouse数据库模式、查询优化、分析以及高性能分析工作负载的数据工程最佳实践. An agent skill from affaan-m/ECC.

    276k GitHub starsUsed in 3 repos~2.3k tokens
    DatabasesAuto-check passed
  • Clickhouse Io

    affaan-m/ECC

    고성능 분석 워크로드를 위한 ClickHouse 데이터베이스 패턴, 쿼리 최적화, 분석 및 데이터 엔지니어링 모범 사례.

    276k GitHub starsUsed in 2 repos~2.3k tokens
    DatabasesAuto-check passed
  • Clickhouse Io

    affaan-m/ECC

    ClickHouse database patterns, query optimization, analytics, and data engineering best practices for high-performance analytical workloads.

    276k GitHub starsUsed in 1 repo~2.7k tokens
    DatabasesAuto-check passed

More from ClickHouse/ClickHouse

All 24 skills in this repo
  • Keeper Stress Analysis

    ClickHouse/ClickHouse

    Analyze ClickHouse Keeper stress-test results from play.clickhouse.com / keeperstresstests data warehouse.

    50k GitHub stars~4.7k tokensUpdated yesterday
    Auto-check passed
  • Perf Comparison

    ClickHouse/ClickHouse

    Evaluate ClickHouse performance test results from existing CI/dashboard data or local perf.py runs.

    50k GitHub stars~3.9k tokensUpdated yesterday
    Auto-check: notes
  • Patch Release Check

    ClickHouse/ClickHouse

    Check whether ClickHouse's supported versions (last 3 majors + latest LTS) have recent stable patch releases, diagnose why the scheduled AutoReleases pipeline failed, and identify which releases…

    50k GitHub stars~4k tokensUpdated yesterday
    Auto-check: notes
  • Alloc Profile

    ClickHouse/ClickHouse

    Analyze a jemalloc (or other) allocation profile in collapsed stack format.

    50k GitHub stars~4.3k tokensUpdated yesterday
    Auto-check passed
  • Bisect

    ClickHouse/ClickHouse

    Bisect a ClickHouse regression using pre-built master binaries from CI.

    50k GitHub stars~1.4k tokensUpdated yesterday
    Auto-check passed
  • Clickhouse PR Description

    ClickHouse/ClickHouse

    Generate PR descriptions for ClickHouse/ClickHouse that match maintainer expectations.

    50k GitHub stars~1.9k tokensUpdated yesterday
    Auto-check passed

Works with

Categories

Questions about Double Check Perf Tests

What does Double Check Perf Tests do?

Locally reproduce ClickHouse CI performance comparison results for a given commit. Double Check Perf Tests is an agent skill from ClickHouse/ClickHouse. Locally reproduce ClickHouse CI performance comparison results for a given commit.

When should I use Double Check Perf Tests?

Double Check Perf Tests fits situations like: wants to double-check; re-run a perf check result — even if they dont name the skill.

How do I install Double Check Perf Tests in Claude Code?

Run `npx skills add ClickHouse/ClickHouse --skill double-check-perf-tests -a claude-code`. Or copy the skill folder (.claude/skills/double-check-perf-tests in ClickHouse/ClickHouse) into .claude/skills/double-check-perf-tests in your project. Claude Code loads it when a task matches its description.

How do I install Double Check Perf Tests in Codex?

Run `npx skills add ClickHouse/ClickHouse --skill double-check-perf-tests -a codex`. Or copy the skill folder (.claude/skills/double-check-perf-tests in ClickHouse/ClickHouse) into .agents/skills/double-check-perf-tests in your project. Codex loads it when a task matches its description.

Can I use Double Check Perf Tests in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ClickHouse/ClickHouse --skill double-check-perf-tests -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/double-check-perf-tests, .gemini/skills/double-check-perf-tests, .github/skills/double-check-perf-tests and .opencode/skills/double-check-perf-tests in your project.

What does Double Check Perf Tests need to run?

Going by SKILL.md and its folder, Double Check Perf Tests needs Python for the scripts in its folder and the command-line tools its instructions call (python3, clickhouse, wget and gh). Our summary lists: Python 3. Its frontmatter pre-approves these tools: Bash, Read, Grep, Glob, WebFetch.

Does Double Check Perf Tests access the network?

SKILL.md contains no URLs. Its commands use wget and gh, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Double Check Perf Tests safe to install?

Our automated static check of SKILL.md found notes only (pre-approves every shell command (allowed-tools: bash)), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.

What licence does Double Check Perf Tests use?

Double Check Perf Tests is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Double Check Perf Tests use?

About 6.4k tokens (SKILL.md is roughly 25k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Double Check Perf Tests?

Skills that share tags, products or a category with Double Check Perf Tests: Chdb SQL (vemetric/vemetric, 395 stars), Debugging Signals Pipeline (PostHog/posthog, 40k stars), Clickhouse Architecture Advisor (vemetric/vemetric, 395 stars) and Clickhouse Io (affaan-m/ECC, 276k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Double Check Perf Tests?

ClickHouse (a GitHub organization) maintains it in ClickHouse/ClickHouse, which has 50,324 GitHub stars. The repository holds 24 skills in this directory. The repository was last updated on October 10, 2026.

Source: ClickHouse/ClickHouse on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.