Across recent projects, I held one rule as a design engineer. Design should arrive as a pull request, not a Figma file that someone else has to rebuild.
The most demanding of them was in cross border payments. The interfaces are full of states most people never see. KYC checks, FX quotes that expire, pending settlement, failed transfers, retries. That is exactly where visual bugs hide and where engineering time quietly disappears, because every one of those states is a screen someone has to design, build and keep consistent.
The traditional loop made this worse. Design produces a file, engineering rebuilds it in code, something drifts, QA finds it late, and a payments screen ships with a state nobody handled. So I changed the input. I stopped treating design as a picture and started treating it as code the rest of the system could read.
Design should arrive as a pull request, not a file to rebuild.
A design system the machine can read
The design system lived in markdown and was versioned like code. Tokens, component variants, accessibility rules and usage constraints, all legible to Claude Code and Cursor rather than locked inside a design tool. That single decision is what made everything after it possible. When the system is context, Claude Code and Cursor can generate a component that already matches it, and I can open the pull request myself.
tokens.md colour, spacing, radius, type scale
components.md variants, states, a11y rules per component
patterns.md payment flows, error and empty states
constraints.md what never to do, brand and compliance limitsA daily bug hunt, before QA
The first routine ran every morning. Claude Code and Cursor swept the open pull requests and the core payment flows and produced a short triage list. Not a vague summary, a fixed output: what looks broken, where, and against which rule.
- Visual regressions. Components that no longer matched the system after a change.
- Token drift. Hard coded colours and spacing that should have referenced the system.
- Missing states. A payment screen with a success and an error state but no pending or retry.
- Accessibility gaps. Contrast, focus order and labels checked against the rules in the system.
Because the design system was the reference, Claude Code and Cursor could judge against something real rather than guess. I was catching design bugs before they reached QA, and often before engineering had looked at the PR at all. Caught early, a bug is a one line review comment. Caught in production on a payments flow, it is an incident.
Taking execution off engineering
The second routine was the design to PR pipeline itself. Because the system was context and not a handoff, UI work shipped as design complete pull requests. The component was built, matched the tokens, handled its states and passed the accessibility rules before an engineer opened it.
That changed where engineering time went. Instead of rebuilding interfaces and chasing visual drift, engineers stayed on the work that genuinely needed them. Payments logic, FX handling, settlement, reliability. I was not adding to their queue, I was removing the part of it that did not need an engineer in the first place.
More shippable work in the pipeline
The throughput followed naturally. When the handoff loop collapses, the designer is no longer downstream waiting for someone to build the work. I was opening pull requests directly, every day, as part of the cadence. More design landed as code, faster, with fewer trips back and forth.
In payments this matters more than in most products, because the cost of a missed state is not a cosmetic glitch, it is a transfer that fails silently or a screen that traps a user mid flow. Enumerating those states up front, as part of the routine, meant fewer of them slipped through.
The principle underneath
None of this was about using more AI. It was about making design a machine readable input so the loop could run. A trigger woke the routine, it read sources it could trust, it judged against the design system, it delivered a fixed output, and the next run improved on the last.
- System as context. A design system you can read as code stops being a reference and becomes an input.
- Fixed outputs. A triage list with the same shape every day, so I could tell if quality improved.
- Failure is output. If a check could not run, the brief said so. No silent gaps on a payments flow.
- Designer as PR author. If you can read your own system as code, you are not downstream. You are merging.
If you take one thing from this, make it the first move. Put your design system somewhere a machine can read it. Everything else, the bug hunt, the design complete PRs, the throughput, is downstream of that one decision. Build loops, not theatre. One painful workflow first.
But the real shift is not just speed. When design already arrives as implementation, the cost of trying another version of a flow drops close to zero. I can explore many variations of the same journey, design for specific and customised scenarios, edge cases, market by market differences, states that only a few users ever hit, and actually ship them as options to test, rather than leaving them as screens in a file that never get built. Testing more, varying more, implementing at a higher level and faster, all of that becomes normal instead of expensive.
That is how I think about my work now.
My job is to shorten the time an engineer spends rebuilding what I already designed, so that time goes into new problems instead.
Design stops being a layer on top of the product and becomes part of the pipeline that moves it forward.
Less downstream, more in the loop. That is the kind of design engineer I am trying to be.
