Show HN: Wasted Cycles – Local wall-clock profiler for AI coding agents
Wasted Cycles is a local profiler that measures how much time AI coding agents spend blocked on compute vs. actively coding. It runs via a single curl command with no install or account, analyzes trace data from tools like Codex and Cursor, and provides detailed breakdowns to identify bottlenecks.
$ curl -fsSL https://raw.githubusercontent.com/zozo123/wasted-cycles/main/run | sh
No install, no account, no daemon, no API key, no upload. The runner downloads a checksum-verified binary into a temporary directory, runs it, and deletes it on exit.
What it answers
How much of a run was spent blocked on a machine instead of coding?
Which one — the compiler, the test suite, CI, containers, or the registry?
Is the same build or test running more than once?
Which coding harness keeps moving on your workload?
What is the highest-impact bottleneck to fix next?
What the output looks like
Built-in demo dataset — not a real measurement
Every number below comes from the synthetic dataset shipped with --demo, reproduced here in HTML. It exists to show the shape of the report, not to make a claim about any harness. Run the profiler on your own traces to get real figures.
Where the time went 4 demo runs · last 7 days
AGENT WORKING
Model work
1h 04m 21%
Read & search
34m 11%
Code changes
1h 10m 23%
Other tool work
6m 2%
BLOCKED ON COMPUTE
Waiting for build
32m 11%
Waiting for tests
29m 10%
Waiting for CI
24m 8%
Waiting for containers
13m 4%
Waiting for agents
12m 4%
Waiting for packages
7m 2%
Repeated build / test
8m 3%
NOT COUNTED
Outside the agent loop
48m
Agent time · blocked on compute 4h 59m · 2h 05m (42%)
Blocked on compute is what this tool measures · human time is shown but never counted
In the terminal the same data is a live TUI: arrow keys switch views, 7 / 0 / y change the lookback window, and q quits.
Supported trace roots
HarnessLocal sourceResolution
Codex~/.codex/sessionsper event
Claude Code~/.claude/projectsper event
Cursor~/.cursor/projects/*/agent-transcriptsper turn
Grok Build~/.grok/sessionsper session
JSONL trace files modified inside the selected window are read in place. Nothing is written back, and nothing leaves the machine.
Cursor only stamps wall-clock time on user turns, so each segment spans a whole turn. Scheduled Cursor agents that tick on a fixed interval are detected and dropped — the pattern that once inflated a session to 120 hours of phantom work.
Method & limits
The profiler reconstructs elapsed segments between timestamped trace events and classifies each segment by the structured action that opened it: the tool that was called, the command that tool ran, or the message that ended a turn. It reads parsed event structure rather than matching text, so a pasted log or a quoted command in a prompt cannot be mistaken for real activity. It measures wall-clock time, not tokens and not cost.
Every segment lands in one of three groups: agent working (model work, reads, edits, other tool calls), blocked on compute (build, tests, CI, containers, packages, sub-agents, repeated work), and not counted (waiting on a human). Agent time is working plus blocked; throughput is the share of agent time that was not spent waiting on a machine. Human time sits beside those numbers so you can see it, and outside them so it cannot distort them.
A build, test, or CI command that runs more than once in a session is reclassified as repeated work, because the machine did the same job twice.
Harnesses record different things. Codex and Claude Code stamp individual events. Cursor transcripts only stamp wall-clock time on user turns, so its runs are reconstructed per turn and each turn takes the most blocking tool category observed inside it; those runs are marked turn on the Runs screen and carry lower confidence. Scheduled Cursor agents that tick on a fixed interval are dropped. Grok Build records only a session start and end, so a Grok run collapses to a single coarse block and is marked turn too. Records the profiler cannot identify are skipped instead of guessed.
Idle time uses two thresholds, because a wait and a walk-away are not the same thing. A gap longer than 2 hours is a session break and is not counted at all, so closing the laptop overnight cannot show up as “waiting for human”. A shorter gap is capped at 30 minutes, and those segments are marked clamped with low confidence. The clamped share of the report is stated on the Method screen and emitted as inferred_ns, so measured time and inferred time stay distinguishable.
“Model work” is an inference proxy, not measured GPU compute time. It is the interval after a user message or a tool result and before the next emitted action. Harnesses expose different levels of timing detail; unless a trace records an exact duration, that interval is an upper bound on real inference. The Method screen in the TUI states this outright, and --json emits a per-segment confidence score so you can weigh each classification yourself.
Prompt text and source code are never stored, rendered, or uploaded. Only timestamps, event kinds, and coarse labels are used.
Flags
--demoOpen the TUI with the built-in synthetic dataset — no traces required.
--days NSize of the window to scan, in days. Defaults to 7.
--ytdScan from January 1 of this year.
--jsonPrint the report as JSON instead of opening the TUI.
--plainPrint a plain-text summary instead of the TUI. Used automatically when output is piped or redirected.
--no-alt-screenRender without the terminal alternate screen.
--versionPrint the version and exit.
In the TUI, press 7, 0, or y (or [ / ]) to switch between 7d, 30d, and YTD without restarting.
$ curl -fsSL https://raw.githubusercontent.com/zozo123/wasted-cycles/main/run | sh -s -- --demo $ curl -fsSL https://raw.githubusercontent.com/zozo123/wasted-cycles/main/run | sh -s -- --days 30 $ curl -fsSL https://raw.githubusercontent.com/zozo123/wasted-cycles/main/run | sh -s -- --ytd --plain $ curl -fsSL https://raw.githubusercontent.com/zozo123/wasted-cycles/main/run | sh -s -- --json