Design Operations

Designers should be able to fix the design bugs they find

Describing a design bug and handing it off takes more time than the fix itself so I built a 'bugbot' AI agent that lets you describe the bug in Slack then reproduces, diagnoses, fixes, and deploys, all while keeping you in the loop.

Designers should be able to fix the design bugs they find
Craig Dennis

Craig Dennis

Filing a design bug takes longer than fixing it

When I review built work against the design and spot something off (a padding value that’s a few pixels out, a colour that didn’t pick up the token, a total that doesn’t use tabular nums) I inspect the code, identify the cause, and then create a GitHub or Linear issue.

The code change is usually tiny, everything around the change is the cost.

The screenshot, the write up, what’s wrong and what ‘right’ looks like, code changes i’ve tried. I drop it in a ticket and leave it to engineering to prioritise it against everything else in their backlog, and they have to stop what they’re doing, load the context I just compressed into a paragraph, and reconstruct the thing I could already see.

By the time it ships I’ve spent longer describing the fix than the fix took. And I’m still the one who QAs it at the end, because I’m the one who knows what it was supposed to look like. Rinse. Repeat.

We don’t want to be doing manual work; that is not where our value lies. Things that are repeatable and automate-able should be done by machines. I build the systems my designers work in, so I should be sure none of us is wasting time on work a machine could do. Describing-then-handing-off a one-line fix is exactly that. The ‘busy work’.

Giving engineers Claude Code doesn’t make this go away

The obvious answer right now is to point an AI coding agent at the backlog. Engineers already do this; a lot of them spend more time orchestrating Claude Code or Codex than writing code by hand, and the fix gets faster.

But a faster engineer is still the wrong person for a design bug. The describing step doesn’t disappear; I still have to write up what’s wrong, because the agent takes instructions from the engineer, who takes them from me. The context still degrades on every hop. And every minor fix I send over is something I’ve pulled an engineer off more impactful work to do, even if the agent makes the fix itself quick.

There’s a murky line of ownership here that I’ve watched cause real friction: the more small fixes flow to engineering, the more small fixes engineering expects to receive, and the further designers drift from the thing they designed.

I wired the whole loop, from a Slack mention to a shipped fix

I built the round trip as a proof of concept. It isn’t live anywhere; it runs locally against a demo app I planted a bug in, and what it proves is that the whole loop holds together end to end. It starts in Slack, because that’s where bugs already get reported, but the input is the least interesting part (more on that below).

Nothing in the pipeline knows what the bug is. There’s no rule that recognises a cart-total error, no hardcoded fix, no hint about which file is wrong. The orchestrator hands the agent two things: the bug report from the thread, and the repo. Every decision after that is the AI’s: what’s broken, why, and how to fix it.

You @mention the agent in a thread where a bug’s been described, and it runs the loop a person would run:

  1. It reads the whole thread up to the mention as the bug report, opens a Linear issue to track, and scores the change with a risk heuristic before any code is touched.
  2. It clones the repo into a throwaway workspace and runs the Claude Agent SDK (the same engine as Claude Code) as the coding brain; the agent reproduces the bug and works out the root cause itself, with every tool call captured as structured data.
  3. The agent writes a failing test that pins the bug, then changes the code until that test and the existing suite pass. It chose both the test and the fix; nothing fed it the answer.
  4. It pushes the branch, opens a real GitHub pull request, and waits for GitHub Actions to run CI against it for real.
  5. It drives a browser to screenshot the fixed result in a separate ‘production’ checkout, distinct from where the fix was written, so the image shows the change live somewhere real.
  6. It merges, deploys, and posts the diagnosis, the fix, and the screenshot back to the Slack thread, with the full investigation trail kept in Linear.

The agent makes every call in that loop, but it isn’t running unsupervised. The pull request is a real one a person can read and reject, CI has to pass before anything merges, and the fixed result still goes to a human before it’s trusted.

Because taste can’t be verified, when a test can’t be created, a PR is left in draft state and the designer is tagged to review.

I used Linear as a passive tracker rather than its built-in agent platform, because I wanted my own orchestrator doing the work and full control over each step. And I split where information lands by who reads it and for how long: the Slack thread gets four milestone posts (started, found it, fixed it, shipped it), while the full investigation trail lives in Linear for whoever picks it up later. Slack is the verdict; Linear is the evidence.

Check out the GitHub repo →

The designer stays in QA, where the judgement is

Here’s the part that matters for who does what. The agent does the describing, the diagnosing, the writing, the PR, the CI wait, the deploy; all the work that was never design work. What it hands back is a screenshot of the fixed thing in a real environment.

That screenshot is the point. The reason it renders in a separate ‘production’ checkout rather than the agent’s own workspace is that a fix only means something once it’s live somewhere real. And the person looking at that screenshot, deciding whether it’s actually right, is me; the designer who knows what it was supposed to look like. QA of design work is design work; the rest of the loop isn’t. The agent gives me back the one step that needed my judgement and takes everything else off my plate.

The real version has to live in the deployment pipeline

Today that sign-off is a screenshot from a loop running on my laptop. The real-world version has to be hosted and wired into a company’s existing deployment infrastructure, so a design fix flows through the same pipeline as every other change instead of the local side channel I built so far.

The piece I most want is a PR preview branch linked back to me: a real, testable URL for the fix rather than a static image. Then I sign off on the live change, click through it, and check the states a screenshot never captures. QA on the actual thing, in the place the work already ships from.

Each run should make the system better at the next one

A version that runs every day would buy something the one-off POC can’t: it would learn. Because the orchestrator starts with no knowledge of the bug, every run is a fresh diagnosis. The agent finds its own way to reproduce the issue, locate the cause, and pin it with a test, and each of those is a worked example of how a class of bug gets caught and fixed.

Right now those examples evaporate when the run ends. The version I want captures them and feeds them back, so the checks that caught a regression and the kind of test that pinned a layout break become part of what the agent reaches for first next time. Each run should leave the system quicker to the same answer.

Slack is only one input

I started in Slack, but the doorway is the swappable part. Reporting a bug in a chat thread still means describing it in words. The real move is to put the trigger where I’m already looking at the broken thing.

Right-click the misaligned element on the live site from a browser extension and say what’s wrong. Fire it from Raycast without leaving the keyboard. Trigger it from inside the design tool, against the actual rendered component. The agent and the round trip stay the same; the input collapses from ‘write a paragraph describing a pixel’ to ‘point at the pixel’. Direct manipulation of the real thing, handed to an agent that ships the fix and shows me the result to sign off.

This does not stop at bugs

The demo has multiple bugs (the cart total ignores quantity, an icon is too large, elements are misaligned) but this workflow expands to almost any change. A designer can request a change to copy, a color change, even a layout change, and engineers receive a PR to review and an audit trail to follow. The machinery doesn’t care which.

Check out the GitHub repo →