Sitemap
Sule Akturk

Sule Akturk

Software Developer

Automating Dependency Handoffs in Azure Boards with Copilot Studio

How I built a low-cost workflow that tells teammates the moment the work they’re waiting on is done.

6 min read5 days ago

--

Every sprint, our team asked the same question in chat: “Is the API ready yet?” A frontend task waits for a backend task. A backend task waits for a design. Nobody wants to keep refreshing the board.

So I built Ready Handoff: a small workflow in Microsoft Copilot Studio. When a work item moves to Test, everyone waiting on it gets a Teams card within a few minutes. If the waiting item has no owner yet, it gets a Ready to Work tag on the board.

In this post I’ll show the design, the build step by step, why it costs almost nothing to run, and the gotchas I hit along the way.

Copilot Studio in one minute

Copilot Studio gives you two building blocks, and picking the right one is most of the design.

  • Agents think. You give them instructions and tools, and they decide what to call and in which order. Great for open-ended questions like “summarize my open items”.
  • Workflows follow steps. A trigger starts them, and every node does exactly one thing: read data, check a condition, loop, send a message. Same input, same result, every time.

Notifying the right person when a work item changes is a rules job, not a thinking job. So Ready Handoff is a workflow with no AI in it at all. That choice is what keeps it reliable and cheap.

Rule of thumb: use AI where judgment adds value, and plain steps everywhere else.

How it works

Press enter or click to view image in full size

Most updates stop at the first decision. Only a fresh move to Test fetches the links, checks each waiting item, and sends a card or adds a tag.

Press enter or click to view image in full size

The same flow as it looks in the Copilot Studio canvas.

Building it, step by step

The whole flow is eight steps. I’ll use a mock project called Phoenix in an organization called contoso, with two work items:

  • #1201 Payments API: add refund endpoint — Backend, owned by Alex Kim
  • #347059 Checkout UI: refund button — Frontend, owned by Jordan Lee, linked to #1201 as its Predecessor

Step 0: Agree on one link type

The automation is only as good as the links on the board. We use Azure DevOps’ built-in Predecessor / Successor link: the waiting item adds the item it waits on as its Predecessor. Unlike Related, this link has a direction, so we always know who is waiting for whom.

In our example, #347059 (Checkout UI) lists #1201 (Payments API) as its Predecessor.

Step 1: Trigger and parse

The trigger is the Azure DevOps connector’s When a work item is updated. It fires for every change in the project, so the next steps must filter fast.

Get Sule Akturk’s stories in your inbox

Join Medium for free to get updates from this writer.

The trigger returns the work item’s fields as one object, so a Parse JSON node turns it into fields I can use in conditions: System_State, System_ChangedDate and Microsoft_VSTS_Common_StateChangeDate.

Step 2: The smart filter

An If/Else node lets the run continue only when both are true:

  • System_State equals Test
  • StateChangeDate equals ChangedDate

The second check is my favourite trick. If the last change was the state change, the two timestamps match. If someone just added a comment to an item that’s already in Test, they don’t. No tags, no extra storage, and no duplicate notifications.

Step 3: Fetch the item with its links

The connector’s Send an HTTP request to Azure DevOps action calls the REST API directly:

GET Phoenix/_apis/wit/workitems/1201?$expand=relations&api-version=7.1

$expand=relations returns every link on the item, including the successors.

Step 4: Keep only the successors

A Filter array node keeps the links whose rel is System.LinkTypes.Dependency-Forward, which is the API's name for Successor. Wrapping the input in coalesce(..., json('[]')) means items with no links simply produce an empty list instead of an error.

Step 5: Loop over the waiting items

A For each loop runs once per successor. Inside, a second HTTP request fetches the successor’s details. The item ID comes from the end of its URL:

last(split(item()?['url'], '/'))

Step 6: Two quick decisions

Two nested If/Else nodes decide what to do:

  1. Is it still open? If the successor is already in Test, Done or Removed, skip it.
  2. Does it have an owner? Check whether System.AssignedTo is empty.

Step 7: Notify with an Adaptive Card

If the waiting item has an owner, the workflow posts an Adaptive Card to them through the Teams Flow bot. The card shows both items and has two buttons to open them.

This is the card shown at the top of this post.

Step 8: No owner? Tag it

If nobody owns the waiting item, two things happen:

  • The owner of the ready item gets a card saying the next item is unassigned.
  • The waiting item gets a Ready to Work tag, so it stands out on the board during planning.

One detail matters here: writing System.Tags through the API replaces all existing tags. The expression first reads the current tags and appends the new one, and skips the write if the tag is already there.

Why it costs almost nothing

The expensive part of Copilot Studio is AI: every time an agent reasons or calls a tool, it consumes Copilot credits. Ready Handoff never calls an agent, so most of what it does is free or close to free.

  • Every update in the project runs only the trigger, Parse JSON and the first If/Else: a few simple workflow actions.
  • HTTP calls to Azure DevOps run only when an item reaches Test. They cost nothing; one call used about 0.8% of the API rate limit.
  • The loop, conditions and tag update also run only when an item reaches Test: a handful of simple actions.
  • Teams cards via Flow bot go out once per waiting person, at no charge.
  • AI agent reasoning never runs, so it costs nothing.

The filter in Step 2 does the heavy lifting. Most updates are comments and field edits, and they stop at the very first condition.

If you want an exact number for your tenant, check consumption in the Power Platform admin center. Pricing changes, so I’m not quoting credit rates here.

What changed for the team

  • No more “is it ready?” messages. The person waiting finds out within minutes, with a direct link.
  • Unowned work stays visible. The Ready to Work tag surfaces unblocked items during sprint planning.
  • Dependencies became explicit. To get notified, people link their items, and the board now shows who waits for whom.
  • Predictable and cheap. No AI in the loop means the same result every time and almost no credit use.

--

--