Why This Design

rdc-cli exists because RenderDoc captures GPU data but traps it behind a GUI. Scripts, CI pipelines, and AI agents cannot access this data programmatically. rdc-cli solves this by exposing capture data through a Unix-friendly CLI with pipe-friendly output.

The Problem

RenderDoc is the industry-standard open-source GPU debugger. It captures every API call, shader, texture, buffer, and render target in a single .rdc file. But all this data is locked inside a GUI application. There is no built-in way to:

  • Query capture data from a script or CI pipeline
  • Diff two captures programmatically
  • Assert rendering correctness in automated tests
  • Let an AI agent explore GPU state iteratively

rdc-cli bridges this gap: it turns .rdc files into streams of tab-separated text that Unix tools can process.

Why a Daemon

A 1 GB capture takes 30–60 seconds to load via OpenCapture(). Reloading for every command is impractical. rdc-cli uses a daemon architecture:

  • rdc open capture.rdc starts a background daemon that loads the capture once
  • Subsequent commands (draws, pipeline, shader, etc.) send JSON-RPC requests over TCP localhost
  • The daemon holds the ReplayController in memory — queries complete in milliseconds
  • rdc close shuts down the daemon

Why TCP instead of Unix sockets? TCP works identically on Linux, macOS, and Windows — zero platform-specific code.

Why single-threaded? RenderDoc's ReplayController must be called from the thread that created it. The daemon uses an asyncio event loop and serializes all requests.

Why TSV by Default

Every command outputs tab-separated values by default. This means:

  • Pipe to grep, awk, cut, sort, diff, join — they all just work
  • Add --json for structured output when you need it (jq, CI assertions, AI agents)
  • Add --jsonl for streaming JSON (one object per line)
  • stderr carries metadata and summaries — stdout is always clean data

Composability in practice:

rdc draws --sort tri_count | tail -5        # heaviest 5 draws
rdc resources --type texture | wc -l        # count textures
rdc shader-map | grep "a1b2" | cut -f1      # find EIDs using a shader

Exit codes follow diff(1) semantics: 0 = success/no difference, 1 = difference found, 2 = error.

Why VFS Paths

Capture data is organized as a virtual filesystem. Two layers with strict separation:

Navigation layer (ls, cat, tree) — pure addressing, no business logic:

rdc ls /draws/142/shader     # → vs  ps
rdc cat /draws/142/shader/ps # → shader disassembly
rdc tree / --depth 2         # → full structure

Query layer (draws, resources, pipeline, etc.) — business logic with filtering:

rdc draws --sort tri_count --limit 10
rdc resources --type texture --sort size

Why not FUSE? FUSE adds kernel module complexity, mount/unmount management, and platform dependencies. Path-string addressing with ls/cat/tree covers every use case without any of that overhead.

Every piece of data has a stable, deterministic path like /draws/142/shader/ps/disasm. AI agents can navigate iteratively — ls to discover, cat to read.

Why CI Assertions

Five purpose-built assertion commands cover the most common CI checks:

  • assert-pixel — verify pixel color at (x,y) within tolerance
  • assert-image — pixel-by-pixel image comparison
  • assert-clean — no validation errors above severity threshold
  • assert-count — numeric metric assertions (draws, triangles, etc.)
  • assert-state — pipeline state value at EID matches expected

For anything else, compose with Unix tools:

test "$(rdc count draws)" -ge 10   # at least 10 draws
rdc log | grep -i error && exit 1  # fail on errors

Why AI-Agent Friendly

rdc-cli is designed for programmatic consumption:

  • Deterministic paths/draws/142/shader/ps always means the same thing
  • Machine-parseable output — TSV and JSON, never mixed formats on stdout
  • Iterative explorationls to discover structure, cat to read data, just like a real filesystem
  • Escape hatchrdc script executes arbitrary Python inside the daemon when the 60 built-in commands aren't enough

The Claude Code skill (rdc install-skill) teaches AI agents the full command vocabulary and VFS namespace.

Key Trade-offs

Design decisions have trade-offs:

Decision Trade-off
Single-threaded daemon No parallel queries, but zero race conditions and simpler code
TSV default (not JSON) Requires --json flag for structured data, but pipes work out of the box
GLSL-only shader edit SPIR-V text assembly causes segfaults in RenderDoc; safety over coverage
No FUSE Cannot mount as real filesystem, but no kernel dependencies
Session token auth Security relies on file permissions (0600), not encryption
TCP localhost No TLS currently; remote capture support is planned for a future phase