← The ADLC library
Field guides · 31

What Azure DevOps automation does, and exactly where it stops

Azure DevOps has four separate automation surfaces and none of them is a general rules engine. Here is what each one is genuinely good at, and the exact point where you have to write code.

You want work item states to keep themselves up to date, you want somebody notified when a change stalls, and you want a weekly number you can trust. You have read that Azure DevOps automates things. You have then spent an afternoon looking for the rules screen, because there is no rules screen.

That is the source of most of the frustration here. Azure DevOps does not have one automation engine. It has four surfaces that each do a slice of the job, and the skill is knowing which slice belongs to which.

The four surfaces, and what each is actually for

Process rules. When you customise a process, you can attach rules to a work item type. These fire on changes to the item itself: make a field required when the state is one thing, set a default, hide a field from a group, block a transition. They are the right tool for keeping a single work item internally consistent, and they are enforced server side, so nobody routes around them by using a different client.

Their shape matters more than their feature list. A process rule is scoped to one work item, triggered by a change to that work item, and it acts on that same work item. Almost every “why can’t Azure DevOps do this” question turns out to be someone asking a process rule to look at a second thing.

Branch policies. Attached to a branch, not a work item. Require a minimum number of approvals, require a successful build, require linked work items, require comment resolution, restrict who can merge. This is the enforcement layer that actually holds, because it sits in the path of the merge rather than reacting after it.

The “require linked work items” policy is the one most teams skip and then regret. It is the difference between a traceable repository and a hopeful one, and it costs nothing but a small amount of goodwill in the first fortnight.

Pipelines. Your general purpose compute. Anything you can express as a script can run on a trigger, on a schedule, or on a completed pipeline. This is where the real automation lives once you outgrow the declarative surfaces, and people underuse it because they think of pipelines as build and release only. A scheduled pipeline that queries the API and posts a summary is a perfectly respectable piece of automation.

Service hooks. The outbound webhook layer. Subscribe to events like work item changes, pushes, pull request activity or completed builds, and send them somewhere else. This is how Azure DevOps talks to anything that is not Azure DevOps.

Process rulesOne work item, reacting to itself. Field consistency and transition guards.
Branch policiesIn the path of the merge. The only surface that can actually stop something.
PipelinesArbitrary logic, on a trigger or a schedule. Where everything else ends up.
Service hooksOutbound events. The bridge to anything outside the product.
Choosing the wrong surface is the most common cause of a week lost to Azure DevOps automation.

Reference a work item from a commit message or a pull request and Azure DevOps records the link, and the work item then shows the development activity against it. The linking syntax differs depending on whether the repository lives in Azure Repos or in GitHub with the Boards integration, so check the current documentation for your setup rather than copying a snippet from a forum post.

At merge time there is an option to complete the linked work items. The exact label has moved between versions, but the behaviour is stable: finish the pull request, and the items it references move to a completed state. For a team whose definition of done really is “merged to main”, that single checkbox removes most manual status updating from the week.

There is also the analytics layer, which keeps a historical record of work item state over time. That history is what makes cycle time and lead time answerable at all, and it is worth understanding that it exists before anyone builds a spreadsheet to reconstruct it by hand.

Four walls, in the order teams hit them

Four specific walls, in the order teams tend to hit them.

Process rules cannot look sideways. A rule on a task cannot ask about the state of its parent, its siblings, or a linked item in another project. Roll up a feature when its children are all done, block a story if a dependency is open, sweep a board on Fridays: none of these are process rule shaped.

There is no scheduled declarative rule. Process rules are change triggered. If you want something to happen because time passed rather than because a field changed, the declarative surfaces have nothing for you. Stale item detection, ageing reports and any “nothing happened for five days” alert has to come from a scheduled pipeline or an external job.

The completion behaviour is coarse. Complete on merge is a single lever. It cannot say “move to ready for test if this branch went to the test environment, but only complete when it reaches production”, and it cannot distinguish a change that merged from one that merged and then got reverted twenty minutes later.

Cross project and cross organisation logic is unsupported territory. If your work lives in one project and your repositories live in another, or your organisation has several, the declarative surfaces stop at the boundary. Everything past that point is the API.

Two steps, and most teams should stop after them

Cheapest first, and most teams should stop after step two.

1. Fix the convention before writing any code. Turn on the branch policy that requires a linked work item, and get people putting the work item reference in the branch name as well as the commit. Everything downstream depends on the link existing. Measure your linking rate: the percentage of merged pull requests that reference a work item. If it is below about nine in ten, no automation you build will produce a number worth reading, because the automation only sees the linked ones and the gap is invisible.

2. Use the merge time completion, and be honest about what done means. If done means merged, use it and move on. If done means deployed, do not use it, because you will spend the next year explaining why the board says finished and the customer disagrees.

3. Move time based logic into a scheduled pipeline. One pipeline on a cron, querying the API, doing whatever the declarative surfaces refuse to. Stale item sweeps, parent rollup, weekly digests. Give it a service identity scoped to the minimum it needs rather than running it as a person, so it keeps working after that person leaves.

4. Use service hooks for anything outbound, rather than polling the API from a script somewhere. Polling is what you build when you have not found the event, and it is always worse.

If the real problem is that your work spans more than one tracker or more than one source control host, none of the above helps, because every surface described here stops at the product boundary. That is the case a cross tool layer exists for, and it is the honest place to mention that we build one: GroundTruth reads Azure DevOps, Jira and Linear with full sync, Asana with read plus coarse write, and GitHub, GitLab and Bitbucket on the source control side. If you are entirely inside Azure DevOps, you do not need us and this article is the whole answer.

Where this breaks down

Some of this is version dependent. Azure DevOps Services and Server do not move in lockstep, and the automation surfaces have changed shape more than once. Treat the descriptions here as the shape of the thing, and confirm the specifics against your own instance.

A scheduled pipeline is real software. Once it has credentials, error handling and a growing set of special cases, it is a service with no owner and no tests. Several teams would be better off tolerating a manual Friday sweep than maintaining that quietly for three years.

Requiring linked work items has a cost. It slows down small fixes and it irritates people who are right that this particular change does not need a ticket. If you turn it on, expect to grant exceptions for a documented set of cases, or you will get ceremonial work items created purely to satisfy the policy, which is worse than no policy.

Derived completion can be wrong in a way that manual status is not. A human moving a card to done is asserting something. A merge trigger is inferring it. When the inference is wrong, nobody notices, because the board looks exactly as confident as it did when it was right.

The strongest objection: maybe your states are the problem. Teams reach for automation when a workflow has eleven states, four of which mean roughly the same thing. Deleting six states fixes more than any rule will, and it takes an afternoon.