Unifying Automation at GitLab: A Decentralized Rule Engine

- Levels
- 3
- Locations
- 101
- Functions
- 16
- Entry points
- 233
Four rows of tally marks counted from the two capability maps. Levels holds at three and functions holds at sixteen; only locations collapses, from ten to one. Entry points, one for each level and location pair that existed, falls with it from twenty-three to three.
Twenty-three places to set up automation, none of them connected to each other.
Automation at GitLab was built in pieces.
Over time, 23 entry points and 16 different functions had evolved to include some form of conditional logic, triggering actions based on user-defined inputs. Each had been built by an independent product team for a narrow use case.
There was no shared framework and no consistent UX. Debugging was painful, visibility was limited, and race conditions were common.
One day, I caught wind of an engineer exploring a new automation feature in isolation.
Earlier research, the AppSec JTBDs, contextual inquiries, and journey mapping, had already shown this was a recurring, systemic pain point.
There was no PM, no roadmap, and no plan. I reached out and we teamed up.
I started with a product-wide audit of every place automation already lived. Each had been built for a narrow use case. Seen together, they showed how much hidden complexity users were carrying.
Instead of centralizing ownership, we decentralized it. Each product team would keep managing its own logic, but on a shared framework of components, templates, and logic handling.

Logic set at the group level flows down to its projects, with overrides where a project needs them and permissions respected throughout. That inverted GitLab’s legacy model, which usually started at the project level and got more complex as it scaled up.
To avoid overwhelming users, I added a library of prebuilt templates that could be customized. That reduced friction and avoided the paradox of choice common in power-user features.
Testing showed that users needed to know, while they were still building, whether the rule would run. The builder was refined around that.
The builder is one screen.

Details holds the rule’s name and whether it is on.

The rule runs when an issue is created.

Conditions are optional. Here the rule applies only to issues less than a day old, with no labels and more than two threads.

When an issue matches, the rule adds the Active label and mentions a user.

Once every part is in place, the status bar reads Automation valid.

Laid flat, the five parts read as a sentence.
You know whether the rule is valid before you press Save.

The automation page lists every automation a team owns in one place. Before this, that logic was spread across 23 entry points.

Any automation in the list opens in a drawer on the right, showing its details, trigger, conditions, actions, and history.

The automation builder, empty on first run, tips into an isometric view and five components lift off its surface one at a time, leaving empty slots behind; each fills in as it lifts, with the form it is filled from shown on the right of the screen, and the status bar reads Automation valid once the last of them is off. Laid flat they read as a sentence: name Active Issues, when an issue is created, and it is less than a day old, and it has no labels, and it has more than two threads, then add a label and mention a user. The parts drop back into the screen and Save is pressed. The automation page then assembles out of the same isometric view, listing every automation in the project with its state, trigger, scope, and last run, Active issues at the top and last run just now. A details drawer then slides in from the right, over the row it opens on.
I ran A/B and B/A usability testing with 12 participants across four primary personas. Each completed two tasks in both the legacy and the new experience. We captured success rates, time on task, reliance on documentation, and qualitative feedback, then refined the interface and how users got feedback while creating an automation.
With no PM and no mandate, the test results made the case.
With early data in hand, we took it to the VP of Product and the three senior PMs who between them oversaw six teams.
Some teams doubted their users could manage the logic. The results showed the system worked and outperformed the status quo.
Within three months, an internal and closed beta.
- Increase in usage
- 15%
- Increase in automation run rate
- 37%
- Fewer errors than legacy
- 28%
Measured 30 days after the beta opened.
The project was deprecated, still in closed beta.
GitLab underwent company-wide layoffs in 2021. The Special Engineering Group was disbanded, and without a formal team to carry the work forward, the project ended there.
The problem was solved in principle, and the beta showed that decentralized automation at GitLab was possible and necessary.














