Skip to main content
Glama

metal-gpu-trace

test

Measure how a Wine or macOS program uses the GPU on an Apple silicon Mac, from the command line or through an AI coding agent: GPU time per frame, frame pacing, FPS and memory, recorded with Instruments' Metal System Trace; whether a translation layer (DXMT, Mullion, MoltenVK) splits the work into too many short encoders; Metal .gputrace captures read without Xcode; and Apple's published facts on each GPU family to read the numbers against. Python 3.9+ standard library, zsh, and Xcode (for xctrace). MIT license. Español.

File

What it does

perf_record.sh

Records a program for N seconds with Metal System Trace and writes <label>_<date>.json (GPU ms per frame, frame intervals, FPS, Metal and resident memory) plus per-frame and memory CSVs. Deletes the .trace afterwards unless KEEP_TRACE=1.

perf_report.py

Summarizes an existing .trace the same way.

gputrace_read.py

Reads a Metal .gputrace capture without Xcode: command buffers, encoders, draws, debug groups. Call names marked probable are not confirmed.

data/apple-gpu-families.json

Apple7 to Apple10: chips, what each family adds, limits that differ, with Apple's sources.

metal_trace_mcp.py

An MCP server over all of the above.

test_metal_trace_mcp.py

Self-check without Instruments: python3 -I test_metal_trace_mcp.py prints ok; pytest runs the same tests.

Recording

PERF_OUT=~/perf-runs zsh perf_record.sh game-d3d12 30 /path/to/wine ~/.wine /path/to/game game.exe
PERF_OUT=~/perf-runs zsh perf_record.sh app-metal 30 native - /path/to/app ./app

Arguments: label, seconds, a Wine directory holding bin/wine (or native), the Wine prefix, the working directory, the program and its arguments. Without PERF_OUT, runs go to ./perf-runs. Reading the trace afterwards takes about a minute on an M1 Pro (87 s for a 10 s recording); through the MCP server the whole call times out after 10 s per recorded second plus 120 s, and an overrun recording leaves no files behind. One recording runs at a time; keep other GPU work off the Mac while it records.

Under Wine, give it 30 s: Wine's start-up takes part of the recording. A recording with under 100 frames is too short to compare.

Related MCP server: XcodeTraceMCP

Disk use

Each recording keeps a JSON summary and three CSVs, about 2 MB for 10 s (most of it the Metal memory samples). The .trace (tens to hundreds of MB) is deleted unless KEEP_TRACE=1. KEEP_RUNS=N keeps only the newest N recordings. PERF_MEMORY=0 skips the Metal memory table, the slowest to read: the summary then has no metal_memory_mib and there is no memory CSV (41 % faster to summarize a 626 MB trace). The MCP tools perf_record and perf_baseline_record offer the same as memory=false.

MCP server

Install

The server runs with uvx from PyPI, with nothing to clone (brew install uv installs it). Recording also needs Xcode installed (xcrun xctrace version prints a version).

uvx metal-gpu-trace

This is the command each client below runs. Desktop apps do not see Homebrew's PATH: give them the full path that which uvx prints (/opt/homebrew/bin/uvx on Apple silicon). uvx keeps the version it first downloaded; run the command once with --refresh after uvx to get the latest. uvx metal-gpu-trace@0.4.0 pins a version.

The server reads these environment variables:

Variable

What it sets

METAL_TRACE_OUT

Where recordings go. Give an absolute path: the default, ./perf-runs, depends on the client's working directory.

METAL_TRACE_WINE

The Wine directory (holding bin/wine) that perf_record uses when the call names none.

WINEPREFIX

The Wine prefix used when the call names none; ~/.wine otherwise.

METAL_TRACE_READ

More directories the tools may read, separated by :.

METAL_TRACE_LOG

off silences the one-line stderr log per call.

KEEP_TRACE

1 keeps each recording's .trace, for trace_tables, trace_query or Instruments.

KEEP_RUNS

Keeps only the newest N recordings.

PERF_ENV

NAME=VALUE pairs, separated by spaces, set for the recorded program.

PERF_INSTRUMENTS

Instruments added to the Metal System Trace template, separated by ; (xcrun xctrace list instruments names them); their tables need the .trace, so pair it with KEEP_TRACE=1.

Claude Code

claude mcp add --scope user metal-trace -e METAL_TRACE_OUT=$HOME/perf-runs -e METAL_TRACE_WINE=/path/to/wine \
  -- uvx metal-gpu-trace
claude mcp list

claude mcp list shows metal-trace as connected. --scope user makes it available in every project; leave it out to add it to the current project only.

Windows

On Windows the server records native programs (perf_record_windows.py); no Wine and no Metal. METAL_TRACE_WINE is not needed: perf_record and perf_attach use native. METAL_TRACE_READ is separated by ;.

Frames come from Intel's PresentMon console application (MIT): one row per Present() of the process, with MsBetweenPresents and the GPU time MsGPUTime. Download PresentMon-<version>-x64.exe from its releases, check its SHA-256 against the one GitHub shows, and call the presentmon_install tool, or put it in %LOCALAPPDATA%\metal-gpu-trace or on PATH, or point PRESENTMON_EXE at it. The user must be an administrator or in the "Performance Log Users" group. Without PresentMon the summary falls back to DWM composition intervals (gpu.source is dwm-composition): they cover the whole desktop, miss games in exclusive full screen, and carry no GPU time. With neither a frame log, PresentMon nor DWM samples, a recording fails; it never invents frames.

What cannot be measured is null, not zero: the 1% low needs 100 frames and the 0.1% low 1000; stutter rate and jitter need two frames; thermal_throttling_detected needs GPU times; a drawstress log holds one mean per line, so its summary (gpu.frame_times) has no frame-level percentiles, stutter or jitter. DWM keeps only intervals between consecutive composed frames and drops a jump of several frames. perf_diagnose calls a large working set with uneven frame times MEMORY_PRESSURE_SUSPECTED: a suspicion, since memory bandwidth is not measured.

winget install --id=astral-sh.uv -e
claude mcp add --scope user metal-trace -e METAL_TRACE_OUT=%USERPROFILE%\perf-runs -- uvx metal-gpu-trace
claude mcp list

To run from a clone instead of PyPI (needs Python 3.9 or newer):

claude mcp add --scope user metal-trace -e METAL_TRACE_OUT=%USERPROFILE%\perf-runs -- python C:\path\to\metal-gpu-trace\metal_trace_mcp.py

In JSON clients use "command": "uvx" (or the full path where uvx prints) and Windows paths with doubled backslashes. Claude Desktop reads %APPDATA%\Claude\claude_desktop_config.json. Run the Windows tests with python -m pytest test_perf_record_windows.py.

Claude Desktop, Cursor and other JSON clients

These apps do not expand ~ or $HOME: write absolute paths.

{
  "mcpServers": {
    "metal-trace": {
      "command": "/opt/homebrew/bin/uvx",
      "args": ["metal-gpu-trace"],
      "env": {
        "METAL_TRACE_OUT": "/absolute/path/to/perf-runs",
        "METAL_TRACE_WINE": "/absolute/path/to/wine"
      }
    }
  }
}

Client

File

Claude Desktop

~/Library/Application Support/Claude/claude_desktop_config.json (Settings, Developer, Edit Config); restart the app

Cursor

~/.cursor/mcp.json

VS Code

.vscode/mcp.json in the project; the top key is servers instead of mcpServers, and the server adds "type": "stdio"

Codex CLI

In ~/.codex/config.toml:

[mcp_servers.metal-trace]
command = "/opt/homebrew/bin/uvx"
args = ["metal-gpu-trace"]
env = { METAL_TRACE_OUT = "/absolute/path/to/perf-runs", METAL_TRACE_WINE = "/absolute/path/to/wine" }

Tools

Tool

Reads or records

perf_record

Records a program and returns its summary; when it ends it stops every program of its Wine prefix, or every process named like a native program. counters=true also records Metal GPU Counters: gpu_counters (the limiters, utilization, occupancy and memory bandwidth of the GPU, with the main limiter) in the summary, at about 40 s of read-back per recorded second; not under Windows

perf_attach

Records a program that is already running, by pid or name, and leaves it running

perf_runs

Lists recordings, newest first, one page at a time, whether each kept its .trace, and the translation layer it ran on (a fingerprint of its Direct3D DLLs, and its Wine)

perf_compare

Compares two recordings: headline numbers, encoders, GPU idle time and each encoder label's GPU ms per frame, largest change first; flags those under 100 frames. markdown=true adds the numbers as Markdown tables for a PR comment; skip_s leaves out the first seconds of each recording (start-up) and recomputes the GPU numbers, hitches and Metal memory without them. perf_gate and perf_panel take skip_s too

perf_baseline

Saves several equal recordings as a named reference and returns the range each number spans across them and spread_pct, how much equal runs differ (the noise a change must beat); alone, lists the references. skip_s saves each run without its first seconds and perf_check applies the same cut to the run it judges

perf_baseline_record

Records the same program count times (default 3) with perf_record's arguments and saves the runs as a reference in one call. skip_s as in perf_baseline

perf_ab

Records the same program with two environments (env_a, env_b: NAME=VALUE pairs) in the order A B B A and says per metric (FPS, 1 % low, GPU ms, stutter) whether B is better, worse or the same: better or worse only when every B value is outside A's range

perf_sweep

Records the same program once per value of one variable (dim, size, example, api or env:NAME), 2 to 8 values, rounds times (every other round in reverse order), and returns per value the median FPS, 1 % low, GPU ms per frame and stutter; with 3 or more numeric values it fits GPU ms per frame on the value (fixed ms and ms per draw for dim) with its r2

perf_check

Judges a recording against a reference: regressed when FPS falls under the range by more than margin_pct (default 3), GPU ms per frame rises over it, or encoders or command buffers per frame exceed it; improved or same otherwise, with the reasons and the full comparison

perf_gate

Checks a recording against budgets you set (FPS and 1% low floors; stutter, p95 GPU ms, hitch and Metal MiB ceilings) and returns pass or fail with each limit and value; a missing number fails

perf_history

Follows FPS, 1% low, GPU ms, stutter, hitches and Metal MiB across the runs whose name starts with a prefix, oldest first, with the change from first to last

perf_panel

Writes <name>.panel.html: a page with GPU time per frame and its hitches, the numbers, Metal memory and, for two runs, A against B. It has no server and loads nothing from the network; the viewer hides or reorders widgets and exports the layout as JSON. With --http, /panel#token=...&runs=a,b shows it live, refreshed every 10 s. layout (tab ids in order) saves panel.json in the runs directory as the default tabs of every panel, the live one included; the GPU counters tab shows when a run has them

perf_export_trace

Writes a recording's GPU frames as <run>.chrome-trace, one slice per frame, for ui.perfetto.dev or chrome://tracing

perf_diagnose

Says whether a recording splits its GPU work into too many short encoders, as translation layers do, with encoders and command buffers per frame, the labels with the most GPU time and the GPU's idle time

trace_tables

Lists the tables of a kept .trace, named by its run or its path

trace_count

Counts the rows of several tables of a kept .trace, in all and per process; by default the tables that matter for a translation layer (GPU intervals, encoders, compiler spills, compiled shaders, allocations, counters, Time Profiler), so an empty one shows before reading it

trace_query

One page of rows of one table, optionally one process

capture_summary

Summarizes a .gputrace; lists its 100 most frequent calls out of calls_total

capture_records

One page of a .gputrace's records

gpu_family

Apple's facts for a family or chip (Apple7, M1 Pro, M3 Max)

presentmon_install

Windows only: downloads PresentMon, checks its pinned SHA-256 and keeps it in %LOCALAPPDATA%\metal-gpu-trace, where perf_record and perf_attach find it; Claude Code asks before every call

workload_list

Lists the test programs workload_fetch can download

workload_fetch

Downloads a test program once, checks its SHA-256 and keeps it in ~/Library/Caches/metal-gpu-trace; Claude Code asks before every call

perf_record takes workload, api (mtl, mtl-x64, vk, d3d11 or d3d12), dim, size and example instead of program, to record a fetched test program (workload_list says what each has). mtl-x64 is native Metal built for x86_64 and run under Rosetta, like Wine's programs; size ("1920x1080") sets drawstress's window. The first workload is bgfx's 17-drawstress (BSD-2, 9.3 MB), built from source by .github/workflows/workloads.yml: a grid of cubes, dim³ draws per frame, with its shaders inside the program. The compare-layer prompt (/metal-trace:compare-layer drawstress d3d12 in Claude Code) records it in native Metal and under the Wine in METAL_TRACE_WINE, then runs perf_diagnose and perf_compare.

The second workload, bgfx-examples (25 MiB), holds nine bgfx examples, each a different load (many cubes, textures, render-target chains, a G-buffer, compute, reflective shadow maps, post-processing, draws the GPU decides): perf_record(workload="bgfx-examples", api="d3d12", example="21-deferred"). Two macOS levers change the Mac under a recording: memory_free_pct (20 to 60) holds the whole Mac at that percentage of RAM free (memory_pressure), and background runs the program under taskpolicy -b, a hard throttle. A small GPU-bound program does not feel the first (drawstress stayed at 728 FPS and its resident memory fell); the second slows it several times over. Repeat a run that uses either.

Reading the numbers across runs

  • A summary says where it ran and what the GPU did: machine (chip, cores, RAM, macOS, screen_locked), gpu_activity (utilization of the device, renderer and tiler, split scenes, GPU recoveries: it covers the whole GPU, not only the program), resource_allocations (allocation events per frame, by type; a running total, not memory in use) and command_buffer_errors.

  • A locked Mac session leaves native Metal windows unpaced: 3 000 to 4 000 FPS against 120 with vsync, on the same examples. Record with the Mac unlocked; perf_compare returns screen when one run was recorded locked and the other not.

  • GPU ms per frame follow the GPU's performance state: a run paced at 120 FPS sits in Minimum and takes more ms for the same work (21-deferred: 1.75 ms paced, 0.27 ms unpaced). perf_compare returns gpu_state when two runs sat in different states, and perf_diagnose returns display_synced_hz when the FPS sits on a display rate. Compare runs paced alike: native Metal and D3D12 under Wine with Mullion, both at 120 FPS, do compare.

api=vk runs the same program through Vulkan on MoltenVK. MoltenVK is not shipped: set METAL_TRACE_MOLTENVK to a directory (no spaces) holding an arm64 libMoltenVK.dylib, such as the one in a Vulkan SDK or brew install molten-vk. The run's layer names MoltenVK with the library's SHA-256, so perf_compare against a native Metal run says it compares two layers. In one measurement at dim=20, 10 s each: native Metal 2 encoders per frame; MoltenVK 13, 91 % of them short, and the GPU idle 89 % of the time (perf_diagnose: too_many_short_encoders true). One pair of runs, not a benchmark.

api=vk is native only. drawstress.exe --vk under Wine needs a Wine built with Vulkan: the Wine of DXMT and Apple's Game Porting Toolkit were tried and both log Wine was built without Vulkan support, so the recording holds no GPU frames. CrossOver's Wine has Vulkan but runs only inside one of its bottles, which was not tried.

The same facts are MCP resources: metal-trace://gpu-families (all) and metal-trace://gpu-families/apple7 to Each saved run is a resource too: metal-trace://runs/<run> reads its summary. apple10. They restate Apple's Metal Feature Set Tables of 21 May 2026, MTLGPUFamily and the M3 tech talk; check a device with supportsFamily.

How it follows the MCP specification and Claude Code's limits:

  • stdout carries only MCP messages; each tool call logs one line to stderr (METAL_TRACE_LOG=off silences it), with no arguments or paths.

  • Lists come in pages (offset, limit, default 50, at most 500) with total and next_offset; a result over 40 000 characters is refused with a hint to ask for a smaller page.

  • Files are read only inside METAL_TRACE_OUT and the directories in METAL_TRACE_READ (separated by :).

  • Failures come back as isError results that say what to do, without stack traces or local paths. Summaries cut absolute paths to file names, so they can be shared.

  • Every xctrace call has a timeout.

HTTP

METAL_TRACE_TOKEN=<secret of 16+ characters> metal-gpu-trace --http [--port N] serves the same tools at POST http://127.0.0.1:8765/mcp (Streamable HTTP, one JSON reply per request), for a client on the same Mac that cannot start a stdio server. Every request needs Authorization: Bearer <token>. It listens on 127.0.0.1 only, refuses a request whose Host or Origin is not localhost or 127.0.0.1 (DNS rebinding), and does not start without the token. Cancel a running call with notifications/cancelled from another connection. There is no progress stream over HTTP, and no remote access: reach another Mac through an SSH tunnel (ssh -L 8765:127.0.0.1:8765 mac), not by opening the port.

Windows tests on a real machine

GitHub's windows-latest has no GPU and no desktop session, so PresentMon and DWM recordings are only tested on a real Windows machine. windows/winbridge-run-tests.ps1 updates a checkout there and runs test_perf_record_windows.py; it is written as a WinBridge task (fixed name, script pinned by SHA-256, no arguments). To register it, copy it to the laptop, set $repo to the checkout's path, take its hash there with Get-FileHash <file> -Algorithm SHA256 (Git may have changed the line endings, so the hash of the copy in this repo is not the one to use), and add a [tasks.<name>] table with script and sha256 to the agent's TOML.

CI gate

metal-gpu-trace check RUN BASELINE [--margin-pct N] runs perf_check without a client and prints one JSON line (verdict, reasons, hints). Exit code 0: same or improved; 1: regressed; 2: could not be judged (no such run or reference, or under 100 frames). Runs are read from METAL_TRACE_OUT. Recording needs Instruments, so the job runs on a self-hosted macOS runner:

jobs:
  perf:
    runs-on: [self-hosted, macOS, ARM64]
    steps:
      - run: zsh perf_record.sh pr native - . ./app
      - run: metal-gpu-trace check "$(ls -t ~/perf-runs/pr_*.json | head -1 | xargs basename -s .json)" main-ref

Credits

  • The record layout of a .gputrace command stream follows tmc/gputrace (MIT); no code is copied. The call ids were matched against Xcode's command list on macOS 27.0.1.

  • GPU family facts: Apple's documents linked above, restated, not quoted.

Available Tools

23 tools
capture_recordsA
Read-only

Returns one page of the records of a .gputrace command stream, with their Metal call names when known.

NameRequiredDescriptionDefault
limitNorows per page, default 50, at most 500
offsetNofirst row, default 0
captureYespath of a .gputrace bundle saved from Xcode, inside METAL_TRACE_OUT or METAL_TRACE_READ

Output Schema

NameRequiredDescription
rowsYes
totalYes
offsetYes
next_offsetYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so safety is covered. The description still adds real behavioral context beyond the annotations: results are paginated ('one page'), call names are best-effort ('when known'), and the operation is scoped to a single capture rather than global state.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence that front-loads the pagination constraint and then the record contents. No filler, nothing repeated from the schema or annotations.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained, and the required capture path is fully described in the schema. What is missing is orientation relative to siblings (trace_count for total rows, trace_query for filtering), which matters for a paged reader in a crowded toolset.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so limit, offset, and the capture path constraint (METAL_TRACE_OUT / METAL_TRACE_READ) are already documented. The description's 'one page' phrasing reinforces the paging model but adds no syntax or format detail beyond the schema, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb-and-resource pair: it returns one page of records from a .gputrace command stream, and notes Metal call names are included when known. That is clear enough to distinguish it from the surrounding perf_* tools, though it never explicitly contrasts with trace_query or trace_tables, which operate on similar row data.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: the tool reads a capture's records, so callers infer it applies after a capture exists. There is no explicit when-to-use guidance, no statement of when to prefer trace_query/trace_tables, and no note that trace_count should be consulted first to page correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

capture_summaryB
Read-only

Reads a Metal .gputrace capture without Xcode: command buffers, encoders, draws, debug groups, and the 100 most frequent call ids out of calls_total.

NameRequiredDescriptionDefault
captureYespath of a .gputrace bundle saved from Xcode, inside METAL_TRACE_OUT or METAL_TRACE_READ

Output Schema

NameRequiredDescription

No output parameters

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds one genuinely useful behavioral trait — that only the 100 most frequent call ids are returned out of calls_total, i.e. the output is truncated — but says nothing about error behavior, cost, or how much of the trace is actually parsed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with no filler; the key scope ('without Xcode') and the contents appear immediately. The trailing enumeration is dense but each item earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be spelled out, and annotations cover the read-only profile; with a single fully documented parameter the definition is nearly complete. The remaining gap is sibling disambiguation against capture_records, which matters given the crowded tool list.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter and schema description coverage is 100%; the schema already explains that 'capture' is a path to a .gputrace bundle inside METAL_TRACE_OUT or METAL_TRACE_READ. The description adds nothing about the parameter beyond the resource type, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific verb (Reads) and resource (Metal .gputrace capture) and enumerates exactly what the summary contains: command buffers, encoders, draws, debug groups, top-100 call ids. It does not, however, contrast itself with the sibling capture_records, so an agent must infer which capture-reading tool to pick.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'without Xcode' hints at the lightweight/headless use case, but there is no explicit when-to-use, no when-not-to-use, and no reference to the obvious alternative capture_records. The agent gets no routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

gpu_familyA
Read-only

Apple's published facts for one GPU family, by family ("Apple7") or chip ("M1 Pro"): its chips, what it adds, its limits, plus the limits shared by all families and the footnotes. Source URLs are in the result.

NameRequiredDescriptionDefault
nameYesa family (Apple7 to Apple10) or a chip (M1 Pro, M2, M4 Max, A17 Pro)

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false. The description adds provenance by noting source URLs are in the result and clarifies that shared limits and footnotes are included, but it does not mention error behavior or caching.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the resource and scope. The colon list is dense but each item clarifies the returned facts.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Low-complexity read-only lookup with a fully described parameter, annotations, and output schema. The description covers scope, result contents, and provenance, leaving no material gap for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single parameter already documents family/chip examples. The description repeats the same valid input forms but adds no formatting or edge-case guidance beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States it returns Apple's published facts for one GPU family and enumerates result contents: chips, additions, limits, shared limits, and footnotes. It does not explicitly differentiate from sibling perf/trace tools, though those are unrelated categories.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implies use for looking up GPU family/chip facts and gives example names such as Apple7 and M1 Pro. It never states when to use this instead of related performance tools or what happens for unsupported names.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

perf_abA
Destructive

Records the same program with two environments in the order A B B A (repeated rounds times, so drift hits both sides equally) and says per metric whether B is better, worse or the same as A, with every value behind it. env_a and env_b are NAME=VALUE pairs separated by spaces; empty means none. Runs are named name-a1, name-b1, ... Each recording takes its seconds plus about a minute to read back. skip_s leaves out the first seconds of every recording (the start-up) when the verdicts are drawn, as perf_compare does; the recordings are whole.

NameRequiredDescriptionDefault
apiNowith workload: mtl (native Metal), mtl-x64 (Metal built for x86_64, run under Rosetta like Wine), vk (Vulkan through MoltenVK: set METAL_TRACE_MOLTENVK), d3d11 or d3d12 (under wine)
dimNowith workload drawstress: side of the cube grid, dim^3 draws per frame
argsNoprogram arguments as in a shell, quotes included
nameYesname for the runs: letters, digits, '.', '_', '-'
sizeNowith a workload that has size_variables (drawstress): the window size, WIDTHxHEIGHT such as 1920x1080
wineNoWine directory holding bin/wine, or native
env_aYesNAME=VALUE pairs for side A, the reference (empty: none)
env_bYesNAME=VALUE pairs for side B, the change under test (empty: none)
memoryNodefault true; false skips the Metal memory table, the slowest to read (about 40 % faster summary): no metal_mib_peak
prefixNoWine prefix, default WINEPREFIX or ~/.wine; ignored with native
roundsNoA B B A rounds, default 1 (4 recordings), at most 5
skip_sNoseconds to leave out at the start of each recording, where shaders compile and resources load; 0 (default) keeps all. The GPU numbers, hitches and Metal memory are recomputed without them
exampleNowith a workload that lists examples in workload_list: the one to run
programNopath of the .exe, or of the macOS binary with wine=native
secondsNorecording length, default 20; use 30 under Wine, whose start-up takes part of it; the export afterwards takes several minutes under Wine
workdirNodirectory the program starts in, default the program's own
countersNodefault false; true also records Metal GPU Counters (gpu_counters in the summary); not under Windows; adds about 40 s of read-back per recorded second
workloadNoa test program from workload_list, fetched with workload_fetch, instead of program
backgroundNomacOS only, default false; true runs the program under taskpolicy -b, which throttles it hard and unevenly (drawstress: 18 to 280 times slower): repeat the run
memory_free_pctNomacOS only, 20 to 60: holds the whole Mac at this percentage of RAM free while recording (memory_pressure), to see how the program behaves short of memory; lower can freeze the Mac

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, it discloses the repeated recording sequence, run-name pattern, substantial read-back time per recording, and the important fact that skip_s changes verdict calculations without truncating the recordings. It does not explain what behavior motivates destructiveHint=true or discuss overwrite and cleanup behavior, which prevents a top score.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description front-loads the purpose and experimental design, then efficiently covers environment syntax, artifacts, runtime cost, and skip_s behavior. Each sentence supplies distinct, useful information without unnecessary background or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Together with the fully documented input schema and existing output schema, the description provides enough context to configure the experiment and understand its cost and analysis behavior. The main remaining gaps are explicit sibling-tool routing and explanation of the destructive or system-side-effect profile signaled by the annotations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3, but the description adds useful operational meaning. It clarifies space-separated env_a/env_b encoding, concrete run naming, how seconds affects elapsed time, how rounds repeats the sequence, and the analysis-only effect of skip_s.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence gives a specific action and scope: record one program under two environments in A B B A order and report per-metric B-versus-A verdicts with supporting values. This clearly conveys the combined recording-and-comparison purpose, but it does not explicitly differentiate the tool from perf_record, perf_compare, or perf_sweep.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The drift-balancing rationale makes the intended context—controlled A/B performance comparisons—clear, and the runtime estimate helps when deciding how many recordings or rounds to request. It lacks explicit selection guidance, such as when to use perf_compare on existing runs or perf_sweep for broader comparisons, and gives no when-not conditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

perf_attachA

Records a program that is already running, by pid or by a name in its command line (Game.exe under Wine), for seconds and returns the same summary as perf_record; the program keeps running. For games started by Steam, CrossOver, NotProton or any launcher: start the game or its benchmark there first.

NameRequiredDescriptionDefault
labelYesname for the run: letters, digits, '.', '_', '-'
processYespid, or a name in the program's command line such as Game.exe
secondsNorecording length, default 20; the export afterwards takes several minutes under Wine

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false, destructiveHint=false and non-idempotent, so the safety profile is covered. The description adds genuinely new behavior: the target keeps running afterwards, the result matches perf_record's summary, and the post-run export takes minutes under Wine. It omits failure modes such as what happens when the pid/name is not found.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core behavior and scope, then the launcher caveat. Slightly run-on across line breaks but no filler sentences.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Output schema exists and the description references it by equivalence ('same summary as perf_record'), so return values need no explanation. Given a non-destructive attach tool with full schema coverage, only error/not-found behavior and permission needs are missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all three parameters are already documented, including the default of 20 for `seconds`. The description's 'Game.exe under Wine' example reinforces the `process` semantics but does not add syntax or matching rules beyond what the schema states.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Records a program that is already running') and adds the scope constraint 'by pid or by a name in its command line', which cleanly separates it from perf_record, the sibling that presumably launches its own target. An agent can tell the two apart without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use it: for programs that are already running, and for games launched by Steam/CrossOver/NotProton where the agent must start the game in the launcher first. It stops short of naming perf_record as the alternative for not-yet-running programs, leaving that inference to the reader.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

perf_baselineA
Idempotent

Names a reference for perf_check, or lists them. With name and runs (names from perf_runs, several runs of the same program recorded with no change between them), it saves copies of their summaries as the reference name, replacing a previous one, and returns the range each number spans across them: that range, not one run, is what perf_check judges against, since repeated runs differ by a few percent, and spread_pct, each range's width in % of its midpoint: the noise of this program on this machine, which a change must exceed. With name alone it shows that reference; with nothing it lists them. With skip_s the reference keeps each run without its first skip_s seconds (the start-up, as perf_compare's skip_s) and perf_check applies the same cut to the run it judges, so both are steady-state; the runs need their per-frame files for that.

NameRequiredDescriptionDefault
nameNoreference name: letters, digits, '.', '_', '-'; alone, shows that reference
runsNorun names from perf_runs to save as this reference, ideally 3 or more equal runs; replaces a previous one
skip_sNoseconds to leave out at the start of each recording, where shaders compile and resources load; 0 (default) keeps all. The GPU numbers, hitches and Metal memory are recomputed without them; perf_check applies the same cut to the run it judges

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=false, idempotentHint=true and destructiveHint=false, but the description adds material facts the annotations don't carry: the call overwrites a previous reference of the same name, and skip_s requires the runs' per-frame files to exist. The overwrite ('replacing a previous one') sits awkwardly with destructiveHint=false, though it is a reversible upsert rather than a true contradiction. The explanation of what the returned numbers mean (ranges, spread_pct as machine noise) also goes beyond the flags.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Every clause carries information — nothing is filler — but the prose is a dense run-on with parenthetical tangents and elided articles, and the three-mode dispatch is buried mid-sentence rather than front-loaded as a list. It is efficient in content but weak in structure, and a re-read is needed to extract the branching logic.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value description isn't required; the description instead covers mode selection, overwrite behavior, the skip_s precondition, and how perf_check consumes the result. The remaining gap is sibling positioning against perf_baseline_record, which matters in a family of 20+ perf tools with overlapping names.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description earns the extra point by adding meaning the schema doesn't: runs should be 'several runs of the same program recorded with no change between them', ideally 3+, and skip_s is coupled to per-frame file availability and mirrored by perf_check. That cross-parameter, cross-tool semantics is real added value rather than restatement.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening clause states a specific verb and resource — it names or lists baselines used as references for perf_check — and the three modes (name+runs, name alone, nothing) are each spelled out, so an agent can tell what the tool does. It loses a point because the near-identically named sibling perf_baseline_record is never mentioned, leaving ambiguity about which of the two to pick.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is dispatched explicitly by argument shape: 'With name and runs... it saves copies', 'With name alone it shows that reference; with nothing it lists them' — a genuine when-to-use map. It also states the upstream dependency (runs come from perf_runs) and that the named reference is what perf_check judges against. It gives no exclusions and never contrasts itself with the sibling perf_baseline_record.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

perf_baseline_recordA
Destructive

Records the same program count times in a row with perf_record's arguments and saves the runs as the reference name for perf_check, returning the range each number spans across them. Runs are named name-1, name-2, ... Each recording takes its seconds plus about a minute to read back. skip_s as in perf_baseline: the reference leaves out each run's start-up.

NameRequiredDescriptionDefault
apiNowith workload: mtl (native Metal), mtl-x64 (Metal built for x86_64, run under Rosetta like Wine), vk (Vulkan through MoltenVK: set METAL_TRACE_MOLTENVK), d3d11 or d3d12 (under wine)
dimNowith workload drawstress: side of the cube grid, dim^3 draws per frame
envNoNAME=VALUE pairs separated by spaces, set in the program's environment
argsNoprogram arguments as in a shell, quotes included
nameYesreference name: letters, digits, '.', '_', '-'
sizeNowith a workload that has size_variables (drawstress): the window size, WIDTHxHEIGHT such as 1920x1080
wineNoWine directory holding bin/wine, or native
countNoequal recordings to make, default 3
memoryNodefault true; false skips the Metal memory table, the slowest to read (about 40 % faster summary): no metal_mib_peak
prefixNoWine prefix, default WINEPREFIX or ~/.wine; ignored with native
skip_sNoseconds to leave out at the start of each recording, where shaders compile and resources load; 0 (default) keeps all. The GPU numbers, hitches and Metal memory are recomputed without them; perf_check applies the same cut to the run it judges
exampleNowith a workload that lists examples in workload_list: the one to run
programNopath of the .exe, or of the macOS binary with wine=native
secondsNorecording length, default 20; use 30 under Wine, whose start-up takes part of it; the export afterwards takes several minutes under Wine
workdirNodirectory the program starts in, default the program's own
countersNodefault false; true also records Metal GPU Counters (gpu_counters in the summary); not under Windows; adds about 40 s of read-back per recorded second
workloadNoa test program from workload_list, fetched with workload_fetch, instead of program
backgroundNomacOS only, default false; true runs the program under taskpolicy -b, which throttles it hard and unevenly (drawstress: 18 to 280 times slower): repeat the run
memory_free_pctNomacOS only, 20 to 60: holds the whole Mac at this percentage of RAM free while recording (memory_pressure), to see how the program behaves short of memory; lower can freeze the Mac

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and non-idempotent, so the safety bar is lower; the description still adds real cost and side-effect context — each recording costs its `seconds` plus about a minute of read-back, and run objects are created under fixed names. It does not say what happens when a reference with that `name` already exists, which is the one mutation detail an agent would want.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four dense sentences, front-loaded with the write-and-name behavior before cost details. Nearly every clause carries information, though the read-back timing remark is slightly buried mid-paragraph rather than separated as a cost caveat.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 19-parameter destructive recording tool with a full output schema, the description covers the action, the artifact naming convention, the relationship to perf_check, and the run-time cost. Return values need not be explained because an output schema exists, and the remaining gap (overwrite semantics) is narrow.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 19 parameters thoroughly. The description reinforces `count` (equal recordings, default 3) and the skip_s cut, including that perf_check applies the same cut, but adds little syntax or meaning the schema lacks; baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: record the same program `count` times, save as reference `name` for perf_check, and return the per-metric range. It explicitly contrasts with perf_record (whose arguments it reuses) and perf_baseline (whose skip_s convention it follows), plus names the artifact naming scheme (`name`-1, `name`-2), so an agent can distinguish it from every sibling.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is clearly implied and partly explicit: the reference is built for perf_check, and repeated recording exists to get the range each number spans. It borrows context from perf_baseline and perf_record rather than stating outright when to pick one of those instead, so there is no explicit exclusion, but the routing signal is strong.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

perf_checkA
Read-only

Judges a recording against a reference saved with perf_baseline: regressed when FPS falls under the reference's lowest FPS by more than margin_pct, GPU ms per frame rises over its highest by more than margin_pct, or encoders or command buffers per frame exceed its highest; improved when a number leaves the range the other way and none regressed; same otherwise. Frame pacing, short encoders and GPU idle time are reported by the comparison but do not decide: they vary too much between equal runs. A run from Windows against a Metal reference (or the reverse) is judged on FPS alone. A reference saved with skip_s judges the run without its first skip_s seconds too (skipped_s says so). Returns the reasons and perf_compare's full comparison against the reference's first run.

NameRequiredDescriptionDefault
runYesa run name from perf_runs
baselineYesa reference name from perf_baseline
margin_pctNohow far outside the reference's range FPS or GPU ms per frame may fall before counting, default 3

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint and openWorldHint; the description goes far beyond by disclosing the exact verdict logic, that frame pacing, short encoders and GPU idle time are reported but never decide, that cross-OS comparisons fall back to FPS alone, and that a skip_s reference trims the run's first skip_s seconds (reported as skipped_s). It also says what is returned: the reasons plus perf_compare's full comparison against the reference's first run.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded in the first clause and the rules follow in a logical order, with the caveats (non-deciding metrics, cross-OS, skip_s) after the core logic. It is a dense single block of prose, but each sentence carries distinct behavioral information rather than restating the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no further explanation, and the description still names the shape of the verdict and returned reasons. For a tool that compares recordings across platforms and time windows, the description covers the decision rules, the exceptions, and the baseline prerequisite without gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so both required params and margin_pct are already documented in the schema. The description adds real meaning for margin_pct by explaining it applies to both the FPS floor and the GPU-ms-per-frame ceiling, but it adds nothing for run or baseline beyond what the schema already says.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Judges a recording against a reference saved with perf_baseline', then enumerates the exact decision rules (FPS under the reference's lowest by more than margin_pct, GPU ms per frame over its highest, encoder/command-buffer counts). It also distinguishes itself from perf_baseline (which saves the reference) and from perf_compare (whose full comparison it returns).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Makes clear the prerequisite (a reference created by perf_baseline) and the conditions under which a run is judged regressed, improved, or same, including the cross-platform Windows/Metal special case. What it does not do is explicitly route the agent away from perf_compare or perf_gate when a raw comparison or a pass/fail gate is wanted, leaving that inference to the sibling names.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

perf_compareA
Read-only

Compares two saved recordings (names from perf_runs), a the reference and b the run after a change: the headline numbers (FPS, GPU ms, frame pacing, memory), then what changed in the GPU work and where: encoders and command buffers per frame, the share of encoders under short_us, the GPU's idle time, and each encoder label's count and GPU ms per frame, largest change first. layer says whether both ran on the same translation layer: with different layers it compares layers, not one change. A Windows run against a Metal run has measure: the GPU ms and Metal memory differ in kind and the encoders exist only in Metal, so use FPS, its lows, stutter and jitter. Recordings with under 100 frames are flagged: too short to compare. With markdown true the result also has markdown: the same numbers as tables for a PR comment. skip_s leaves out the first seconds of each recording, where shaders compile and resources load: the GPU numbers, hitches and Metal memory are recomputed from the per-frame files without them, and skipped_s says it; thermal state, process memory and encoders stay whole-run. screen appears when one run was recorded with the screen locked and the other not: FPS is then not comparable.

NameRequiredDescriptionDefault
aYesrun name from perf_runs: the reference, such as the run before a change
bYesrun name from perf_runs: the run to compare against a
skip_sNoseconds to leave out at the start of each recording, where shaders compile and resources load; 0 (default) keeps all. The GPU numbers, hitches and Metal memory are recomputed without them
markdownNoalso return the numbers as Markdown tables, default false
short_usNoan encoder under this GPU time counts as short: 10, 25 (default), 50, 100, 250, 500 or 1000

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say readOnlyHint and openWorldHint=false; the description goes well beyond by disclosing the diagnostic flags it emits (layer, measure, screen, skipped_s), the short-recording threshold that alters the comparison, and exactly which metrics are recomputed under skip_s versus which remain whole-run. That level of disclosure about conditional result semantics is unusual and directly useful for interpreting output.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The first sentence front-loads the purpose and headline metrics, and subsequent clauses each carry a distinct conditional fact rather than filler. It is dense to the point of being hard to scan (no lists, minor typos like 'a the reference'), but almost no sentence could be deleted without losing a conditional rule.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only comparison tool with an output schema and two required name parameters, the description covers source of names, comparison semantics, the three cases where the comparison is not apples-to-apples, and the effect of each optional parameter. Nothing an agent needs in order to call it correctly or interpret a flag is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema for skip_s: thermal state, process memory and encoders stay whole-run while GPU numbers, hitches and Metal memory are recomputed, and skipped_s reports the exclusion. It also ties markdown output to a concrete use (PR comment) and restates short_us's role only lightly.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: compares two saved recordings from perf_runs, with 'a' as the reference and 'b' as the post-change run, and it enumerates what is compared (FPS, GPU ms, frame pacing, memory, encoder counts, GPU idle). An agent can distinguish this from perf_runs (listing) and from capture tools without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit conditional guidance: recordings under 100 frames are flagged as not comparable, different translation layers mean layer-vs-layer comparison, a Windows-vs-Metal pair should be judged on FPS/lows/stutter/jitter, and a locked-vs-unlocked screen makes FPS non-comparable. It lacks routing against nearby siblings such as perf_ab, perf_gate or perf_check, so the alternative-selection guidance is strong on data conditions but absent on tool selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

perf_diagnoseA
Read-only

Says whether a saved recording splits its GPU work into too many short encoders, the pattern of translation layers such as DXMT, Mullion or MoltenVK, with the numbers behind it: encoders and command buffers per frame, the share of short encoders, the labels with the most GPU time and the GPU's idle time. Read the idle time together with the FPS: a program waiting for vsync idles too. Defaults come from bgfx 17-drawstress on an M1 Pro: 7 encoders per frame and 50% under 25 us under Mullion, 2 and 2% in native Metal.

NameRequiredDescriptionDefault
runYesa run name from perf_runs
short_usNoan encoder under this GPU time counts as short: 10, 25 (default), 50, 100, 250, 500 or 1000
short_shareNoshare of short encoders from which the verdict is yes, default 0.25
min_encodersNoencoders per frame (median) from which the verdict can be yes, default 4

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so safety is covered; the description adds genuine context by disclosing the verdict's decision basis (short-encoder share, encoders per frame), reference values from bgfx 17-drawstress on an M1 Pro under Mullion vs native Metal, and an important interpretation caveat that idle time must be read alongside FPS because a vsync-bound program also idles.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The verdict and evidence list are front-loaded in the first sentence, with the interpretation caveat and the reference numbers following. It is dense but every sentence carries decision-relevant information; the M1 Pro benchmark sentence is long but functions as calibration rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not enumerate return values, and it correctly focuses on the decision logic, interpretation caveat and reference thresholds. For a four-parameter read-only diagnostic tool this is close to sufficient, missing only explicit routing versus sibling diagnostics.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description earns extra credit by giving concrete calibration values (7 encoders/frame and 50% short under Mullion versus 2 and 2% in native Metal) that tell the agent what magnitudes of short_us, short_share and min_encoders are meaningful. It does not restate the per-parameter defaults that the schema already documents.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verdict ('says whether a saved recording splits its GPU work into too many short encoders') plus the secondary axis it inspects (translation layers like DXMT/Mullion/MoltenVK) and the evidence it returns. An agent knows exactly what question this tool answers. It stops short of naming a sibling (e.g. perf_compare or perf_check) to draw the boundary explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied: the tool takes a run name from perf_runs, so it operates on already-recorded data, and the vsync/idle-time note tells the agent how to interpret results. But there is no explicit when-to-use versus perf_compare, perf_check or perf_baseline, nor any stated prerequisite beyond the run parameter.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

perf_export_traceA
Idempotent

Writes a recording's GPU frames as a Chrome trace file, <run>.chrome-trace in the runs directory, that ui.perfetto.dev and chrome://tracing open: one slice per GPU frame, from its start for its GPU time (the sum of its encoders' time, so a frame with parallel encoders can show shorter than it took), with the compute, fragment and vertex split as arguments. Returns the file name and the number of frames.

NameRequiredDescriptionDefault
runYesa run name from perf_runs

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false, destructiveHint=false, idempotentHint=true and openWorldHint=false, so the safety profile is covered; the description adds real value beyond that by naming the output path/filename pattern and disclosing a subtle caveat that a frame's GPU time can be shorter than its wall time when encoders run in parallel. It stops short of stating overwrite behavior for a pre-existing trace file, which would complete the picture.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence that opens with the action and artifact before descending into slice semantics. It is dense but nearly every clause carries information; the trailing phrase 'with the compute, fragment and vertex split as arguments' is the weakest and slightly ambiguous part.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter tool with an output schema and full annotations, the description covers the output location, format compatibility, and the meaning of the trace contents. Only the runs-directory location and existing-file overwrite semantics are left unstated.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is only one parameter and schema description coverage is 100%, with the schema itself explaining that 'run' is 'a run name from perf_runs'. The description adds no further syntax or format detail, so the schema is doing all the work and baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Writes') plus a precise resource ('a recording's GPU frames as a Chrome trace file') and names the exact artifact produced. An agent can immediately distinguish this file-producing export from sibling query tools like trace_query, trace_tables, and capture_summary.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: the mention that ui.perfetto.dev and chrome://tracing can open the output hints that this is for visual inspection, but the description never says when to prefer this over trace_query or capture_summary, nor when not to use it. No prerequisites (e.g. that a run must already be recorded) are stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

perf_gateA
Read-only

Checks a recording against budgets and says pass or fail: a floor for FPS and the 1% low, a ceiling for the stutter rate, the p95 GPU ms per frame, the hitch count and the peak Metal MiB. Give at least one. A number the recording lacks fails its budget (value null): a gate must not pass on missing data. Returns each budget with its limit, the value and whether it held. Use it as a bar a change must clear, where perf_check judges against equal runs. skip_s leaves out the first seconds of the recording (the start-up), as perf_compare does.

NameRequiredDescriptionDefault
runYesa run name from perf_runs
skip_sNoseconds to leave out at the start of each recording, where shaders compile and resources load; 0 (default) keeps all. The GPU numbers, hitches and Metal memory are recomputed without them
fps_minNothe FPS must be at least this
hitches_maxNothe number of hitches at most this
metal_mib_maxNothe peak Metal memory in MiB at most this
gpu_ms_p95_maxNothe p95 GPU ms per frame at most this
fps_1pct_low_minNothe 1% low FPS must be at least this
stutter_rate_pct_maxNothe share of stutter frames, in %, at most this

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so safety is covered structurally. The description adds genuinely useful semantics beyond that: missing data fails its budget rather than passing, and skip_s causes GPU numbers, hitches and Metal memory to be recomputed. Return shape is described but an output schema already exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The pass/fail purpose and the missing-data rule are front-loaded, which is good. However the budget enumeration and the skip_s note are crammed into a run-on block, and the skip_s sentence at the end repeats territory the schema already covers.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an eight-parameter read-only gate with a full schema and an output schema, the description covers the non-derivable parts: the at-least-one requirement, the fail-closed policy on missing data, and the sibling routing. Nothing an agent needs to invoke it correctly is absent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents every parameter, which sets the baseline at 3. The description contributes the cross-parameter rule ('Give at least one') and the null-fails-on-missing-data semantics for the budget params, but the skip_s explanation largely restates the schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Checks a recording against budgets and says pass or fail') and immediately enumerates the exact budget dimensions (FPS floor, 1% low, stutter rate ceiling, p95 GPU ms, hitch count, peak Metal MiB). It also explicitly contrasts itself with a sibling: 'where perf_check judges against equal runs.'

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a concrete when-to-use rule ('a bar a change must clear') and names the alternative tool with the condition that selects it (perf_check for equal-run comparison). It also states a hard invocation constraint ('Give at least one' budget) that would otherwise cause a confusing error.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

perf_historyA
Read-only

Lists the recordings whose name starts with prefix, oldest first, with their FPS, 1% low, GPU ms, stutter, hitches and peak Metal MiB, and the change from the first to the last: how a number moved over a series of runs, such as one recording per version of a translation layer. Read a trend as real only when it exceeds the spread_pct that perf_baseline reports for equal runs. Runs from Windows and Metal in one series are flagged: their GPU ms and memory do not compare. skip_s leaves out the first seconds of each recording (the start-up), as perf_compare does.

NameRequiredDescriptionDefault
limitNonewest runs to keep, default 50
prefixYesthe start of the run names to follow: letters, digits, '.', '_', '-'
skip_sNoseconds to leave out at the start of each recording, where shaders compile and resources load; 0 (default) keeps all. The GPU numbers, hitches and Metal memory are recomputed without them

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint and openWorldHint, so the description carries the real behavioral load and does so: it states the sort order ('oldest first'), the cross-platform comparability caveat ('Runs from Windows and Metal in one series are flagged: their GPU ms and memory do not compare'), and the noise-floor interpretation rule. These are non-obvious traits an agent could not infer from annotations or schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Verb and resource are front-loaded and nearly every clause carries information (ordering, metrics, delta, noise threshold, platform caveat, skip semantics). It is a single dense paragraph whose parentheticals ('the start-up', the translation-layer example) border on redundant given the schema, but nothing is padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need not be explained, and the description still covers ordering, comparability caveats, and the interpretation rule that an agent would otherwise miss. The remaining gap is the limit/sort interaction (capped at the newest N but reported oldest-first), which affects how a caller reasons about truncation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, and the description largely mirrors it — skip_s as 'the start-up' seconds with recomputed metrics is already spelled out in the schema, and prefix semantics are already there. The one genuinely additive phrase is ordering ('oldest first'), which is not a parameter but interacts with limit ('newest runs to keep, default 50'); the description does not explain that tension.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource ('Lists the recordings whose name starts with `prefix`') and then names the exact output content (FPS, 1% low, GPU ms, stutter, hitches, peak Metal MiB) plus the first-to-last delta. It also frames the intended shape of the series ('one recording per version of a translation layer'), which separates it from one-off tools like perf_compare or perf_baseline that it explicitly references.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a clear usage context — following a number across a series of runs — and an interpretive rule ('Read a trend as real only when it exceeds the spread_pct that perf_baseline reports for equal runs'), which is real when-to-use guidance. What it lacks is an explicit exclusion: it never says when an agent should choose perf_compare or perf_ab instead of this tool, only that skip_s behaves 'as perf_compare does'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

perf_panelA
Idempotent

Writes one HTML file, <name>.panel.html in the runs directory, that shows one or two recordings in a browser without a server: GPU time per frame with the hitches marked, the numbers (FPS and its lows, frame time, jitter, stutter, memory, thermal state), Metal memory over time and, for two runs, A against B. The file holds the data itself, no path, and loads nothing from the network; the viewer can hide and reorder the widgets and export the layout as JSON. preset fps is the timeline, numbers and memory; compare (two runs) puts A against B first. skip_s leaves out the first seconds of each recording (the start-up), as perf_compare does. layout (tab ids in the order to show) is saved as panel.json in the runs directory and becomes the default tab order of every panel, the live one too, until the viewer changes it in the browser; ids left out are hidden but can be switched back on; tabs are summary, ab, frames, encoders, counters, memory and data, and a panel.json you wrote yourself, or copied from the panel's Layout JSON, works the same. Returns the file name, the runs, the frames shown and the file's bytes.

NameRequiredDescriptionDefault
nameYesname for the panel file: letters, digits, '.', '_', '-'
runsYesone or two run names from perf_runs; with two, the first is A, the reference
layoutNotabs to show, in order: summary, ab, frames, encoders, counters, memory, data; saved as panel.json in the runs directory as the default for every panel
presetNofps (default) or compare (needs two runs)
skip_sNoseconds to leave out at the start of each recording, where shaders compile and resources load; 0 (default) keeps all. The GPU numbers, hitches and Metal memory are recomputed without them

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, it discloses the real behavioral traits: a file is written into the runs directory, the file is self-contained and loads nothing from the network, and — most importantly — the `layout` argument is persisted as panel.json and becomes the default tab order for every panel, including the live one, until a viewer changes it. That global side effect is exactly the kind of context annotations cannot carry. It stops short of saying what happens on name collision or overwrite of an existing panel.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Content is front-loaded on the artifact, which is right, but the body is a dense run-on with stacked clauses ('The file holds the data itself, no path, and loads nothing from the network') and buries the significant layout/persistence side effect mid-paragraph. Several fragments ('no path', 'A against B') cost parsing effort without adding precision.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a five-parameter write tool it covers everything an agent needs: required inputs, file destination and naming, all preset and layout consequences, and even the return payload (file name, runs, frames shown, byte size) which is also backed by an output schema. Nothing material is missing given the annotation and schema richness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% so the baseline is 3; the prose adds genuine meaning on top by giving the tab id vocabulary (summary, ab, frames, encoders, counters, memory, data), the semantics of omitted ids (hidden but switchable back on), the persistence behavior of layout, and the fact that a hand-written or copied panel.json works identically. skip_s and preset meanings largely restate the schema rather than extend it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a concrete verb and artifact: 'Writes one HTML file, `<name>.panel.html` in the runs directory', then enumerates exactly what the artifact shows (GPU time per frame with hitches, FPS/lows/jitter/stutter/memory/thermal, Metal memory, A vs B). It also anchors itself to siblings by name ('as perf_compare does', runs 'from perf_runs'), so an agent can separate this from perf_ab/perf_compare without reading schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes clear what the output is for (viewing one or two recordings in a browser without a server) and explains which preset fits which case ('compare' needs two runs), but it never states when an agent should choose this over perf_compare, perf_ab or the live panel. Usage is implied from the artifact type rather than routed explicitly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

perf_recordA
Destructive

Records program (an .exe under Wine, or a macOS binary with wine="native"), or a test program fetched with workload_fetch (workload, api, dim), for seconds with Metal System Trace and returns its summary: GPU ms per frame, frame intervals, FPS, Metal and resident memory (memory=false skips the Metal memory table, the slowest to read). When it ends it stops every program of that Wine prefix (wineserver -k), or every process named like the program with native. counters=true also records Metal GPU Counters (gpu_counters in the summary: the units the GPU waited on, its utilization, occupancy and memory bandwidth); it adds about 40 s of read-back per recorded second.

NameRequiredDescriptionDefault
apiNowith workload: mtl (native Metal), mtl-x64 (Metal built for x86_64, run under Rosetta like Wine), vk (Vulkan through MoltenVK: set METAL_TRACE_MOLTENVK), d3d11 or d3d12 (under wine)
dimNowith workload drawstress: side of the cube grid, dim^3 draws per frame
envNoNAME=VALUE pairs separated by spaces, set in the program's environment
argsNoprogram arguments as in a shell, quotes included
sizeNowith a workload that has size_variables (drawstress): the window size, WIDTHxHEIGHT such as 1920x1080
wineNoWine directory holding bin/wine, or native
labelYesname for the run: letters, digits, '.', '_', '-'
memoryNodefault true; false skips the Metal memory table, the slowest to read (about 40 % faster summary): no metal_mib_peak
prefixNoWine prefix, default WINEPREFIX or ~/.wine; ignored with native
exampleNowith a workload that lists examples in workload_list: the one to run
programNopath of the .exe, or of the macOS binary with wine=native
secondsNorecording length, default 20; use 30 under Wine, whose start-up takes part of it; the export afterwards takes several minutes under Wine
workdirNodirectory the program starts in, default the program's own
countersNodefault false; true also records Metal GPU Counters (gpu_counters in the summary); not under Windows; adds about 40 s of read-back per recorded second
workloadNoa test program from workload_list, fetched with workload_fetch, instead of program
backgroundNomacOS only, default false; true runs the program under taskpolicy -b, which throttles it hard and unevenly (drawstress: 18 to 280 times slower): repeat the run
memory_free_pctNomacOS only, 20 to 60: holds the whole Mac at this percentage of RAM free while recording (memory_pressure), to see how the program behaves short of memory; lower can freeze the Mac

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Critical behavior beyond the annotations is spelled out: at the end it kills every program in the Wine prefix (wineserver -k) or every process named like the program with native — exactly the destructiveHint in concrete terms. It also quantifies costs and risks: counters adds ~40 s read-back per recorded second, memory=false is ~40% faster, background throttling is 18-280x, memory_free_pct can freeze the Mac, and the export takes minutes under Wine.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action and its return value are front-loaded in the first sentence, with caveats following. It is dense and long-sentenced but nearly every clause carries operational information; only the memory=false phrasing is repeated from the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 17-parameter, destructive, long-running recording tool with an output schema, the description covers prerequisites (workload_fetch/list), side effects (process killing), timing implications, and platform caveats. Nothing an agent needs to call it safely is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents every parameter, and much of the description's parameter talk (memory=false, counters=true, wine=native, seconds=30) restates it. The added value is mainly the program/workload mutual exclusivity and the consequence of the kill behavior tied to the wine choice, which is a modest increment over the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Records' a program or a fetched workload under Metal System Trace) and enumerates what the summary contains (GPU ms/frame, frame intervals, FPS, memory). It also draws the program-vs-workload boundary that separates it from workload_fetch/workload_list and the non-recording siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete guidance on selecting inputs: pass `program` for a local .exe/binary or `workload` for a test program from workload_list, set wine=native for macOS binaries, use 30 s under Wine because start-up eats into the recording. It does not explicitly say when to prefer perf_attach, perf_ab, or perf_sweep instead, so routing among siblings is left partly implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

perf_runsA
Read-only

Lists the saved recordings, newest first, with frames, FPS, GPU ms per frame, memory peaks and the translation layer each ran on (fingerprint and Wine, or native).

NameRequiredDescriptionDefault
limitNorows per page, default 50, at most 500
offsetNofirst row, default 0

Output Schema

NameRequiredDescription
rowsYes
totalYes
offsetYes
next_offsetYes

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered for free. The description contributes two genuinely new facts: result ordering ('newest first') and which metrics are surfaced per row; however, enumerated row fields are largely redundant with the existing output schema, and pagination/truncation behavior is never mentioned.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One sentence, front-loaded with the verb and resource plus the ordering guarantee, then the payload. Nothing is padding and nothing essential is buried.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

A read-only, two-param list tool with a full output schema and complete annotation coverage needs little more than this, and the description covers scope, ordering and payload. The only real gap is whether more pages exist beyond the returned window and how callers should page through large result sets.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both `limit` (default 50, max 500) and `offset` (default 0) are already fully documented with defaults and bounds. The description adds nothing about paging strategy or ordering interaction with offset, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb+resource ('Lists the saved recordings') and enumerates what each row contains (frames, FPS, GPU ms/frame, memory peaks, translation layer), so there's no ambiguity about what the tool returns as opposed to perf_record or perf_compare. It stops short of naming a sibling it is not, which keeps it at 4 rather than 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied by 'Lists the saved recordings' – an agent can infer this is the read-only inventory tool, but the description never says when to reach for it over perf_baseline, capture_records or perf_compare, nor any exclusions. No explicit when/when-not guidance is present.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

perf_sweepA
Destructive

Records the same program once per value of one variable (dim, example, api, size, or env:NAME for an environment variable) and returns, per value, the median of FPS, 1 % low, GPU ms per frame and stutter, and with 3 or more numeric values the straight line GPU ms per frame follows (fixed ms plus ms per draw for dim, per unit otherwise) with its r2. With rounds above 1 the values run in opposite order every other round, so drift hits all alike. Runs are named name--r; each takes its seconds plus about a minute to read back.

NameRequiredDescriptionDefault
apiNowith workload: mtl (native Metal), mtl-x64 (Metal built for x86_64, run under Rosetta like Wine), vk (Vulkan through MoltenVK: set METAL_TRACE_MOLTENVK), d3d11 or d3d12 (under wine)
dimNowith workload drawstress: side of the cube grid, dim^3 draws per frame
envNoNAME=VALUE pairs separated by spaces, set in the program's environment
argsNoprogram arguments as in a shell, quotes included
nameYesname for the runs: letters, digits, '.', '_', '-'
sizeNowith a workload that has size_variables (drawstress): the window size, WIDTHxHEIGHT such as 1920x1080
wineNoWine directory holding bin/wine, or native
memoryNodefault true; false skips the Metal memory table, the slowest to read (about 40 % faster summary): no metal_mib_peak
prefixNoWine prefix, default WINEPREFIX or ~/.wine; ignored with native
roundsNorounds, default 1, at most 5 and at most 24 recordings in all; every other round runs the values in reverse
skip_sNoseconds to leave out at the start of each recording, where shaders compile and resources load; 0 (default) keeps all. The GPU numbers, hitches and Metal memory are recomputed without them
valuesYes2 to 8 values of the variable, such as [10, 20, 30] for dim
exampleNowith a workload that lists examples in workload_list: the one to run
programNopath of the .exe, or of the macOS binary with wine=native
secondsNorecording length, default 20; use 30 under Wine, whose start-up takes part of it; the export afterwards takes several minutes under Wine
workdirNodirectory the program starts in, default the program's own
countersNodefault false; true also records Metal GPU Counters (gpu_counters in the summary); not under Windows; adds about 40 s of read-back per recorded second
variableYeswhat changes between runs: dim, example, api, size, or env:NAME for an environment variable
workloadNoa test program from workload_list, fetched with workload_fetch, instead of program
backgroundNomacOS only, default false; true runs the program under taskpolicy -b, which throttles it hard and unevenly (drawstress: 18 to 280 times slower): repeat the run
memory_free_pctNomacOS only, 20 to 60: holds the whole Mac at this percentage of RAM free while recording (memory_pressure), to see how the program behaves short of memory; lower can freeze the Mac

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations only declare destructive/not-idempotent; the description goes well beyond them by disclosing real cost ('each takes its seconds plus about a minute to read back'), a hard budget ('at most 5 and at most 24 recordings in all'), the interleaved reverse-order scheduling used to spread drift, and the naming scheme of every run created. These are exactly the traits an agent needs before committing an expensive mutation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded in one long sentence, but that sentence crams in return-value detail (FPS, 1 % low, GPU ms, stutter, slope and r2) that an output schema already covers, and the phrasing is compressed to the point of ambiguity ('1 % low', 'the straight line GPU ms per frame follows'). Useful content, but not tight.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 21-parameter, destructive, long-running sweep the description supplies the critical operational facts: time cost, recording budget, ordering strategy, artifact naming and the memory=false speed trade-off. With an output schema present, return-value explanation is optional, and only the sibling-routing advice is genuinely absent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so parameters are already documented and the baseline is 3. The description adds only marginal meaning beyond the schema — chiefly the run-naming template tying `name` to values and rounds, and the reversal semantics of `rounds` — while most parameter behavior lives in the schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening clause states a specific verb and resource: 'Records the same program once per value of one variable', which immediately separates it from a single-run tool like perf_record. The enumerated variable space (dim, example, api, size, env:NAME) and the per-value aggregation make the sweep semantics unmistakable, though no sibling is named explicitly to complete the contrast.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage context is implied by the parameter-space enumeration and by notes like 'with rounds above 1...' and 'with 3 or more numeric values', so an agent can infer when the tool fits. However, nothing states when to choose perf_sweep over perf_ab, perf_compare or perf_baseline, and no prerequisites (e.g. needing workload_fetch first) appear in the description itself.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

presentmon_installA
Idempotent

Windows only: downloads Intel's PresentMon console application (MIT) from its GitHub release, checks its SHA-256 against the one this package pins, and keeps it in %LOCALAPPDATA%\metal-gpu-trace, where perf_record and perf_attach find it; later calls reuse it. It needs administrator rights or the Performance Log Users group to run.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond annotations: names the network source (GitHub release), discloses SHA-256 verification against a pinned hash, gives the on-disk location (%LOCALAPPDATA%\metal-gpu-trace), and states the privilege requirement (admin or Performance Log Users group). This is exactly the auth/network/artifact context annotations cannot convey, and it is consistent with readOnlyHint=false/openWorldHint=true.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the platform constraint and packs platform, source, verification, destination, reuse semantics, and privileges into three dense sentences with no filler. Slightly long and run-on in the first sentence, but every clause carries distinct information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no parameters, rich annotations, and an output schema to carry return values, the description supplies everything else an agent needs: OS constraint, network dependency, integrity check, install path, idempotency, and privilege prerequisite.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Zero parameters, so the baseline of 4 applies; there is nothing for the description to disambiguate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb+resource: downloads Intel's PresentMon console app from its GitHub release and installs it locally. The 'Windows only' qualifier and repeated references to perf_record/perf_attach make it clearly distinguishable from every sibling, which are all consumers rather than installers.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states the tool is what perf_record and perf_attach depend on and that later calls reuse the installed copy, so an agent knows to install before recording. It lacks an explicit 'skip this if already installed / use X instead' clause, but idempotentHint and 'later calls reuse it' cover the main decision.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

trace_countA
Read-only

Counts the rows of several tables of a kept .trace, in all and per process, so a recording's useful tables show before reading them: a table with 0 rows needs another instrument or Xcode, not a bigger page.

NameRequiredDescriptionDefault
traceYesa run name from perf_runs whose trace_kept is true, or the path of a .trace
tablesNotable names from trace_tables; default the tables that matter for a translation layer

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds real behavioral context — counts are aggregated both globally and per process, and zero counts mean a different tool/Xcode is needed — but says nothing about cost, trace size limits, or failure modes when a trace is missing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One sentence, front-loaded with the verb and object, and the rationale clause earns its place by explaining what the counts are for. Only minor cost is the slightly convoluted trailing clause.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Two well-described params, an output schema that carries the return shape, and annotations covering safety — the description supplies the one thing structured fields can't: the interpretive rule that zero rows means a different instrument. Complete enough to call correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%: the trace param already documents the run-name-or-path forms and tables already points at trace_tables with its default. The description adds no parameter-level detail beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: counts rows of tables in a kept .trace, both overall and per process. The triage framing ("so a recording's useful tables show before reading them") makes it distinguishable from the table-listing and querying siblings, though it never names them explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"so a recording's useful tables show before reading them" plus the 0-row guidance gives a clear posture: run this as a cheap pre-check before querying, and treat zero-row tables as a signal to switch instruments rather than retry with a larger page. No explicit exclusion or named alternative (trace_query) is given, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

trace_queryA
Read-only

Returns one page of rows of one table of a .trace as {column: value}, optionally only one process's rows.

NameRequiredDescriptionDefault
pidNokeep only this process's rows
limitNorows per page, default 50, at most 500
traceYesa run name from perf_runs whose trace_kept is true, or the path of a .trace
offsetNofirst row, default 0
schemaYesa table name that trace_tables lists, such as metal-gpu-intervals

Output Schema

NameRequiredDescription
rowsYes
totalYes
offsetYes
next_offsetYes

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so safety is covered; the description adds genuinely new behavior: results are paginated ('one page'), shaped as {column: value}, and can be scoped to a single process. It stops short of disclosing what happens with an invalid table name or an offset past the end of the data.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with no filler; the core behavior (paged row read from one table of a trace) comes first and the optional pid narrowing follows. Nothing could be removed without losing information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not explain return values, and all five parameters are documented in the schema. For a read-only paginated query tool the coverage is nearly complete; only error/edge-case behavior and the trace_tables dependency are unstated.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with limit defaults/maximum, offset default, pid filtering, and the trace_kept/table-name constraints all documented in the schema itself. The description only restates the pid filter ('optionally only one process's rows') and the paging concept, adding little beyond the structured fields, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: returns one page of rows from one table of a .trace, plus the return shape ({column: value}) and the optional pid narrowing. It implicitly separates itself from trace_tables (which lists tables) and trace_count (which counts), but never names those siblings, so an agent must infer the division of labor.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description says what the tool returns but never states when to reach for it versus trace_tables, trace_count, or capture_records. There is no mention of the prerequisite that 'schema' must first come from trace_tables, and no guidance on paging strategy (e.g. advancing offset until a short page). Usage is only inferable from the wording.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

trace_tablesA
Read-only

Lists the data tables (schemas) a .trace recording holds; recordings keep their .trace only with KEEP_TRACE=1.

NameRequiredDescriptionDefault
traceYesa run name from perf_runs whose trace_kept is true, or the path of a .trace

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds a meaningful behavioral caveat: recordings retain their .trace only when KEEP_TRACE=1, which affects whether this tool can be used at all. It stops short of saying what happens when the trace is absent or not kept.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The definition is a single front-loaded sentence with no wasted wording. The KEEP_TRACE=1 clause is relevant but slightly terse and could be mistaken for a condition on this tool rather than on trace retention.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only listing tool with an output schema, annotations, and full parameter coverage, the description is complete enough to call it correctly. The main missing piece is explicit sibling routing, but the core behavior and trace-retention caveat are present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the parameter description already explains that the trace argument can be a run name with trace_kept=true or a .trace path. The tool description does not add format or validation details beyond that. Baseline 3 is appropriate when the schema covers the single parameter thoroughly.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: it lists the data tables (schemas) contained in a .trace recording. This distinguishes it from query/count siblings by output type, though it does not name those siblings explicitly. The purpose is clear without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: an agent can infer this is a discovery step before querying a trace, but the description gives no explicit when-to-use guidance or comparison to trace_query or trace_count. The KEEP_TRACE=1 note is a retention prerequisite rather than routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

workload_fetchA
Idempotent

Downloads a test program from this project's GitHub releases once, checks its SHA-256 against the one this package pins, and keeps it in ~/Library/Caches/metal-gpu-trace; later calls reuse it. The programs are built from source by the project's workloads workflow.

NameRequiredDescriptionDefault
nameYesa workload name from workload_list, such as drawstress

Output Schema

NameRequiredDescription

No output parameters

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotentHint=true, openWorldHint=true, and destructiveHint=false, so the description's job is mostly to add context. It does: network fetch from GitHub, SHA-256 integrity verification against a pinned hash, and a specific cache path in ~/Library/Caches/metal-gpu-trace. It omits what happens on checksum mismatch or offline failure, which keeps it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the action and integrity check, followed by cache location and reuse semantics. The provenance sentence about the workloads workflow justifies trust in the binary rather than padding, and no sentence is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With rich annotations and an output schema present, the description covers the essential mechanics: source, verification, cache location, and idempotent reuse. The remaining gap is failure behavior (checksum mismatch, no network), which matters for an open-world download but is a modest omission.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single `name` parameter is documented in the schema with an example and a pointer to workload_list. The description itself adds no parameter guidance, so the baseline of 3 is appropriate given the schema carries the load.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific action and resource: downloading a test program from the project's GitHub releases, verifying its SHA-256, and caching it locally. An agent can distinguish this from read-only siblings like workload_list or perf_run because the caching and download behavior is stated. It stops short of explicitly directing agents to workload_list for valid names, which would sharpen differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'later calls reuse it' implies the tool is safely re-invoked and that a first call seeds the cache, which is useful implied guidance. However, there is no explicit when-to-use instruction (e.g. 'call before perf_run if the workload is not cached') and no stated alternatives or exclusions relative to workload_list or presentmon_install.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

workload_listA
Read-only

Lists the test programs workload_fetch can download, such as bgfx's drawstress: what each measures, its size, license and APIs, and whether it is already downloaded.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so safety is covered. The description adds useful context about what is enumerated, including the 'whether it is already downloaded' state, which tells the agent results reflect local state rather than a static catalog. No mention of caching or freshness, keeping it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with the resource first and the informative payload (measures, size, license, APIs, download status) following. No filler or restated title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return structure need not be explained; the description still summarizes the fields, and for a zero-parameter read-only list tool nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so per the baseline there is nothing for the description to disambiguate. Schema coverage is 100% and the description correctly implies a parameterless call.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Lists the test programs workload_fetch can download') and even gives a concrete example (bgfx's drawstress). It clearly positions itself as the enumeration counterpart to the sibling workload_fetch, so an agent can distinguish them without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

By tying the listing to 'programs workload_fetch can download,' it implicitly tells the agent to call this first to discover valid workload names before fetching. It does not explicitly state when-not to use it or name alternatives beyond workload_fetch, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 9 tool updatesv0.18.0
    • Addedperf_ab
    • Changedperf_baseline1 field changed
      • addedInput schema / properties / skip_s
        Added value: +{
        +  "description": "seconds to leave out at the start of each recording, where shaders compile and resources load; 0 (default) keeps all. The GPU numbers, hitches and Metal memory are recomputed without them; perf_check applies the same cut to the run it judges",
        +  "type": "number"
        +}
    • Changedperf_baseline_record8 fields changed
      • changedInput schema / properties / api / description
        Previous value: -"with workload: mtl (native Metal), d3d11 or d3d12 (under wine)"New value: +"with workload: mtl (native Metal), mtl-x64 (Metal built for x86_64, run under Rosetta like Wine), vk (Vulkan through MoltenVK: set METAL_TRACE_MOLTENVK), d3d11 or d3d12 (under wine)"
      • addedInput schema / properties / background
        Added value: +{
        +  "description": "macOS only, default false; true runs the program under taskpolicy -b, which throttles it hard and unevenly (drawstress: 18 to 280 times slower): repeat the run",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / counters
        Added value: +{
        +  "description": "default false; true also records Metal GPU Counters (gpu_counters in the summary); not under Windows; adds about 40 s of read-back per recorded second",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / env
        Added value: +{
        +  "description": "NAME=VALUE pairs separated by spaces, set in the program's environment",
        +  "type": "string"
        +}
      • addedInput schema / properties / example
        Added value: +{
        +  "description": "with a workload that lists examples in workload_list: the one to run",
        +  "type": "string"
        +}
      • addedInput schema / properties / memory_free_pct
        Added value: +{
        +  "description": "macOS only, 20 to 60: holds the whole Mac at this percentage of RAM free while recording (memory_pressure), to see how the program behaves short of memory; lower can freeze the Mac",
        +  "type": "integer"
        +}
      • addedInput schema / properties / size
        Added value: +{
        +  "description": "with a workload that has size_variables (drawstress): the window size, WIDTHxHEIGHT such as 1920x1080",
        +  "type": "string"
        +}
      • addedInput schema / properties / skip_s
        Added value: +{
        +  "description": "seconds to leave out at the start of each recording, where shaders compile and resources load; 0 (default) keeps all. The GPU numbers, hitches and Metal memory are recomputed without them; perf_check applies the same cut to the run it judges",
        +  "type": "number"
        +}
    • Changedperf_compare1 field changed
      • addedInput schema / properties / skip_s
        Added value: +{
        +  "description": "seconds to leave out at the start of each recording, where shaders compile and resources load; 0 (default) keeps all. The GPU numbers, hitches and Metal memory are recomputed without them",
        +  "type": "number"
        +}
    • Addedperf_gate
    • Addedperf_history
    • Addedperf_panel
    • Changedperf_record7 fields changed
      • changedInput schema / properties / api / description
        Previous value: -"with workload: mtl (native Metal), d3d11 or d3d12 (under wine)"New value: +"with workload: mtl (native Metal), mtl-x64 (Metal built for x86_64, run under Rosetta like Wine), vk (Vulkan through MoltenVK: set METAL_TRACE_MOLTENVK), d3d11 or d3d12 (under wine)"
      • addedInput schema / properties / background
        Added value: +{
        +  "description": "macOS only, default false; true runs the program under taskpolicy -b, which throttles it hard and unevenly (drawstress: 18 to 280 times slower): repeat the run",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / counters
        Added value: +{
        +  "description": "default false; true also records Metal GPU Counters (gpu_counters in the summary); not under Windows; adds about 40 s of read-back per recorded second",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / env
        Added value: +{
        +  "description": "NAME=VALUE pairs separated by spaces, set in the program's environment",
        +  "type": "string"
        +}
      • addedInput schema / properties / example
        Added value: +{
        +  "description": "with a workload that lists examples in workload_list: the one to run",
        +  "type": "string"
        +}
      • addedInput schema / properties / memory_free_pct
        Added value: +{
        +  "description": "macOS only, 20 to 60: holds the whole Mac at this percentage of RAM free while recording (memory_pressure), to see how the program behaves short of memory; lower can freeze the Mac",
        +  "type": "integer"
        +}
      • addedInput schema / properties / size
        Added value: +{
        +  "description": "with a workload that has size_variables (drawstress): the window size, WIDTHxHEIGHT such as 1920x1080",
        +  "type": "string"
        +}
    • Addedperf_sweep
  2. 18 tool updatesv0.10.1
    • Changedcapture_records1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "properties": {
        +    "next_offset": {
        +      "type": [
        +        "integer",
        +        "null"
        +      ]
        +    },
        +    "offset": {
        +      "type": "integer"
        +    },
        +    "rows": {
        +      "type": "array"
        +    },
        +    "total": {
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "total",
        +    "offset",
        +    "rows",
        +    "next_offset"
        +  ],
        +  "type": "object"
        +}
    • Changedcapture_summary1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "type": "object"
        +}
    • Changedgpu_family1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "type": "object"
        +}
    • Changedperf_attach2 fields changed
      • changedInput schema / properties / seconds / description
        Previous value: -"recording length, default 20; the export afterwards takes about a minute"New value: +"recording length, default 20; the export afterwards takes several minutes under Wine"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "type": "object"
        +}
    • Changedperf_baseline1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "type": "object"
        +}
    • Changedperf_baseline_record3 fields changed
      • addedInput schema / properties / memory
        Added value: +{
        +  "description": "default true; false skips the Metal memory table, the slowest to read (about 40 % faster summary): no metal_mib_peak",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / seconds / description
        Previous value: -"recording length, default 20; use 30 under Wine, whose start-up takes part of it; the export afterwards takes about a minute"New value: +"recording length, default 20; use 30 under Wine, whose start-up takes part of it; the export afterwards takes several minutes under Wine"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "type": "object"
        +}
    • Changedperf_check1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "type": "object"
        +}
    • Changedperf_compare2 fields changed
      • addedInput schema / properties / markdown
        Added value: +{
        +  "description": "also return the numbers as Markdown tables, default false",
        +  "type": "boolean"
        +}
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "type": "object"
        +}
    • Changedperf_diagnose1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "type": "object"
        +}
    • Addedperf_export_trace
    • Changedperf_record3 fields changed
      • addedInput schema / properties / memory
        Added value: +{
        +  "description": "default true; false skips the Metal memory table, the slowest to read (about 40 % faster summary): no metal_mib_peak",
        +  "type": "boolean"
        +}
      • changedInput schema / properties / seconds / description
        Previous value: -"recording length, default 20; use 30 under Wine, whose start-up takes part of it; the export afterwards takes about a minute"New value: +"recording length, default 20; use 30 under Wine, whose start-up takes part of it; the export afterwards takes several minutes under Wine"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "type": "object"
        +}
    • Changedperf_runs1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "properties": {
        +    "next_offset": {
        +      "type": [
        +        "integer",
        +        "null"
        +      ]
        +    },
        +    "offset": {
        +      "type": "integer"
        +    },
        +    "rows": {
        +      "type": "array"
        +    },
        +    "total": {
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "total",
        +    "offset",
        +    "rows",
        +    "next_offset"
        +  ],
        +  "type": "object"
        +}
    • Addedpresentmon_install
    • Changedtrace_count1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "type": "object"
        +}
    • Changedtrace_query1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "properties": {
        +    "next_offset": {
        +      "type": [
        +        "integer",
        +        "null"
        +      ]
        +    },
        +    "offset": {
        +      "type": "integer"
        +    },
        +    "rows": {
        +      "type": "array"
        +    },
        +    "total": {
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "total",
        +    "offset",
        +    "rows",
        +    "next_offset"
        +  ],
        +  "type": "object"
        +}
    • Changedtrace_tables1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "type": "object"
        +}
    • Changedworkload_fetch1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "type": "object"
        +}
    • Changedworkload_list1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "type": "object"
        +}
  3. 14 tool updatesv0.7.1
    • Changedcapture_records1 field changed
      • addedInput schema / properties / capture / description
        Added value: +"path of a .gputrace bundle saved from Xcode, inside METAL_TRACE_OUT or METAL_TRACE_READ"
    • Changedcapture_summary1 field changed
      • addedInput schema / properties / capture / description
        Added value: +"path of a .gputrace bundle saved from Xcode, inside METAL_TRACE_OUT or METAL_TRACE_READ"
    • Addedperf_attach
    • Addedperf_baseline
    • Addedperf_baseline_record
    • Addedperf_check
    • Changedperf_compare3 fields changed
      • addedInput schema / properties / a / description
        Added value: +"run name from perf_runs: the reference, such as the run before a change"
      • addedInput schema / properties / b / description
        Added value: +"run name from perf_runs: the run to compare against a"
      • addedInput schema / properties / short_us
        Added value: +{
        +  "description": "an encoder under this GPU time counts as short: 10, 25 (default), 50, 100, 250, 500 or 1000",
        +  "type": "integer"
        +}
    • Addedperf_diagnose
    • Changedperf_record6 fields changed
      • addedInput schema / properties / api
        Added value: +{
        +  "description": "with workload: mtl (native Metal), d3d11 or d3d12 (under wine)",
        +  "type": "string"
        +}
      • addedInput schema / properties / dim
        Added value: +{
        +  "description": "with workload drawstress: side of the cube grid, dim^3 draws per frame",
        +  "type": "integer"
        +}
      • addedInput schema / properties / prefix / description
        Added value: +"Wine prefix, default WINEPREFIX or ~/.wine; ignored with native"
      • addedInput schema / properties / workdir / description
        Added value: +"directory the program starts in, default the program's own"
      • addedInput schema / properties / workload
        Added value: +{
        +  "description": "a test program from workload_list, fetched with workload_fetch, instead of program",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "label",
        -  "program"
        -]New value: +[
        +  "label"
        +]
    • Addedtrace_count
    • Changedtrace_query3 fields changed
      • addedInput schema / properties / pid / description
        Added value: +"keep only this process's rows"
      • addedInput schema / properties / schema / description
        Added value: +"a table name that trace_tables lists, such as metal-gpu-intervals"
      • addedInput schema / properties / trace / description
        Added value: +"a run name from perf_runs whose trace_kept is true, or the path of a .trace"
    • Changedtrace_tables1 field changed
      • addedInput schema / properties / trace / description
        Added value: +"a run name from perf_runs whose trace_kept is true, or the path of a .trace"
    • Addedworkload_fetch
    • Addedworkload_list
  4. 8 tool updatesv0.2.0
    • First observedcapture_records
    • First observedcapture_summary
    • First observedgpu_family
    • First observedperf_compare
    • First observedperf_record
    • First observedperf_runs
    • First observedtrace_query
    • First observedtrace_tables

TDQS

A3.9/5.0

Scored across 23 tools

Disambiguation5/5

Despite many perf_* tools, each has a clearly distinct role: record, attach, sweep, A/B compare, baseline, check, gate, history, diagnose, panel, export, and run listing. Similar-sounding pairs like perf_baseline versus perf_baseline_record are differentiated by whether they consume existing runs or record new ones. The trace and capture tools are also cleanly separated by operation and artifact type.

Naming Consistency4/5

The set follows a consistent snake_case convention with useful domain prefixes such as perf_, trace_, capture_, workload_, and gpu_. Names are not strictly verb_noun throughout—there are noun-style names like perf_runs, perf_history, and perf_panel—but the grouping is readable and predictable. Minor deviations do not impede tool selection.

Tool Count4/5

At 23 tools the surface is large, but this is a broad GPU profiling suite covering recording, comparison, baselines, gates, traces, captures, workload setup, and environment inspection. Each tool appears to earn its place, though the count is slightly heavy and could be streamlined. It is not an extreme mismatch for the stated scope.

Completeness4/5

The tool set covers the main lifecycle: fetching workloads, recording or attaching, saving baselines, comparing, checking, gating, diagnosing, visualizing, exporting traces, and inspecting raw trace/capture data. The main noticeable gap is management of saved artifacts, such as deleting or renaming recordings and baselines. That is a minor omission rather than a blocker for core profiling workflows.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    Not graded
    maintenance
    Enables GPU profiling and performance analysis via NVIDIA Nsight Systems, allowing agents to profile binaries and aggregate statistics for kernels, memory copies, and NVTX ranges. It supports advanced analysis through interval tree construction and structural queries on profiling reports.
    5
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables AI agents to profile iOS/macOS apps using Xcode Instruments, automate simulator interactions, and get structured performance data for optimization.
    37
    26 npm
    20
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables coding agents to profile and disassemble GPU kernels, benchmark and compare candidate rewrites against baselines, and run an autonomous speedrun loop that verifies and records results.
    10
    32 PyPI
    Apache 2.0