Can your AI agent read a waveform?

WaveQ indexes VCD files so your agent can ask for exact values.

git clone https://github.com/IshaanDugar/waveq
Get it on GitHub

Free and open source (AGPL-3.0).
Needs Python 3.10 or newer and nothing else.

sample.vcd
$var wire 1 ! clk $end
$var wire 1 # valid $end
$var wire 1 $ ready $end
…
#10
0!
1"
#15
1!
1#
b10100101 %
#20
0!
1$
…
#40
0!
0&
0'
0#
0$
sample.vcd, drawn
0 10 20 30 40 50 ns clk valid ready data 00 A5 16 ns

valid is 1 from 15 to 40 ns

value_at("tb.valid", "16ns")
{
  "ok": true,
  "data": {
    "signal": "tb.valid",
    "time": "16ns",
    "value": "1",
    "held_from_time": "15ns",
    "held_until_time_exclusive": "40ns"
    …
  }
}
In this dump, # stands for valid. The answer on the right comes from the three lit lines.

What’s in a VCD file?

A simulator writes a line each time a signal changes, after a line that says when. Your waveform viewer draws this picture from those lines.

0 10 20 30 40 50 ns clk rst_n valid ready data[7:0] 00 A5 psel penable
examples/sample.vcd from 0 to 50 ns. Each step in a trace is one line of the file.

Why not paste the VCD into the chat?

It won’t fit, and the agent would end up guessing.

QuestionRaw VCD in the chatWith WaveQ
SizeMillions of tokens for 12 MBwindow_digest sends a short summary
NamesGuesses the hierarchyresolve_signals finds exact paths
Repeat questionsReads the file againCache reattaches in about 1.5 ms
Many signalsOne scan per signalvalues_at reads eight in under 1 ms

How does it answer so fast?

It reads the dump once into three SQLite tables, then looks things up.

tb.valid changes runs edges 0 ns → 0 15 ns → 1 40 ns → 0 0 from 0 to 15 ns 1 from 15 to 40 ns 0 from 40 to 51 ns x_exit rise fall value_at 16 ns
changes
Every transition, in order.
runs
Each stretch a value held. value_at finds yours.
edges
Rises, falls, x and z. Clocks come from here.
0 10 20 30 40 50 ns clk psel penable cycle 3, sampled at 34 ns
psel rises on the 25 ns edge itself, so a flop clocked there still sees 0.

Can it find when something happened?

With a clock, find_times reads each signal one tick before the edge, as a flip-flop does.

find_times({
  "conditions": [
    {"signal": "psel", "value": "1"},
    {"signal": "penable", "value": "1"}],
  "clock": "clk"})
cycle 3, edge at 35ns, sampled at 34

What if the answer isn’t there?

It says so, and ok: false tells the agent to stop.

  • value_at("tb.vaild", "16ns")not_found No signal matched 'tb.vaild'
  • value_at("tb.valid", "0.5ns")value_at_failed '0.5ns' is not representable at timescale 1ns
  • changes("tb.valid", "0ns", "500ns")time_out_of_range time 500ns is outside waveform range 0ns..50ns

How do I connect it?

Install once, then add one entry to your MCP client.

terminal
git clone https://github.com/IshaanDugar/waveq
cd waveq
python -m venv .venv
.venv/bin/pip install -e .

Windows: .venv\Scripts\pip install -e .

claude_desktop_config.json
{
  "mcpServers": {
    "waveq": {
      "command": "/path/to/waveq/.venv/bin/python",
      "args": ["-m", "waveq.mcp_server"],
      "cwd": "/path/to/waveq"
    }
  }
}
~/.cursor/mcp.json
{
  "mcpServers": {
    "waveq": {
      "command": "/path/to/waveq/.venv/bin/python",
      "args": ["-m", "waveq.mcp_server"],
      "cwd": "/path/to/waveq"
    }
  }
}
~/.codex/config.toml
[mcp_servers.waveq]
command = "/path/to/waveq/.venv/bin/python"
args = ["-m", "waveq.mcp_server"]
cwd = "/path/to/waveq"

Guides: every client, Codex on Windows.

Point your agent at a dump.