Christoph Linne

Instead of always having the same person share the Kanban board in our MS Teams daily stand-up, we now rotate this task automatically.


We automate the process using Power Automate, ensuring the rotation and messaging happens consistently.

captain_kanban_flow.png

Recurrence

We schedule the flow to run every weekday at 08:00 AM:

{
  "type": "Recurrence",
  "recurrence": {
    "frequency": "Week",
    "interval": 1,
    "startTime": "2025-07-01",
    "timeZone": "W. Europe Standard Time",
    "schedule": {
      "hours": [
        "8"
      ],
      "minutes": [
        0
      ],
      "weekDays": [
        "Monday",
        "Tuesday",
        "Wednesday",
        "Thursday",
        "Friday"
      ]
    }
  }
}

List Team Members

List all members from our MS Teams group:

{
  "type": "OpenApiConnection",
  "inputs": {
    "parameters": {
      "groupId": "abc123456-1234-5678-9abc-abc123abc123"
    },
    "host": {
      "apiId": "/providers/Microsoft.PowerApps/apis/shared_office365groups",
      "connection": "shared_office365groups",
      "operationId": "ListGroupMembers"
    }
  },
  "runAfter": {}
}

Initialize members variable:

{
  "type": "InitializeVariable",
  "inputs": {
    "variables": [
      {
        "name": "members",
        "type": "array",
        "value": "@outputs('List_group_members')?['body/value']"
      }
    ]
  },
  "runAfter": {
    "List_group_members": [
      "Succeeded"
    ]
  }
}

Select Captain

Randomly pick a captain for the day:

{
  "type": "InitializeVariable",
  "inputs": {
    "variables": [
      {
        "name": "captainIndex",
        "type": "integer",
        "value": "@rand(0, sub(length(variables('members')), 1))"
      }
    ]
  },
  "runAfter": {
    "members": [
      "Succeeded"
    ]
  }
}

Assign the captain:

{
  "type": "InitializeVariable",
  "inputs": {
    "variables": [
      {
        "name": "captain",
        "type": "string",
        "value": "@variables('members')[variables('captainIndex')]['givenName']"
      }
    ]
  },
  "runAfter": {
    "captainIndex": [
      "Succeeded"
    ]
  }
}

Assign Backups

Select backup members using modulo wrapping so the list wraps around — no matter who is picked as captain:

{
  "type": "Compose",
  "name": "backup1",
  "inputs": "@variables(‘members’)[mod(add(variables(‘captainIndex’), 1), length(variables(‘members’)))]",
  "runAfter": {
    "captain": [
      "Succeeded"
    ]
  }
}
{
  "type": "Compose",
  "name": "backup2",
  "inputs": "@variables(‘members’)[mod(add(variables(‘captainIndex’), 2), length(variables(‘members’)))]",
  "runAfter": {
    "backup1": [
      "Succeeded"
    ]
  }
}

This ensures the selection always wraps around — if the captain is the last person in the list, the backups are simply picked from the beginning.

Note: This requires at least 3 team members to work correctly.

Post Message to Teams

Finally, send the daily Kanban crew message to the group chat:

{
  "type": "OpenApiConnection",
  "inputs": {
    "parameters": {
      "poster": "Flow bot",
      "location": "Group chat",
      "body/recipient": "19:meeting_1234566778889@thread.v2",
      "body/messageBody":
        "✈️ Prepare for take-off!  <br>
        Today’s stand-up flight crew is cleared for Kanban duty.<br><br>
        • 🧑‍✈️ Captain Kanban (shares the board): **@{variables('captain')}**  <br>
        • 🧑‍✈️ First Officer (backup): @{outputs('backup1')['givenName']}  <br>
        • 🧑‍🔧 Flight Engineer (last resort): @{outputs('backup2')['givenName']}"
    },
    "host": {
      "apiId": "/providers/Microsoft.PowerApps/apis/shared_teams",
      "connection": "shared_teams",
      "operationId": "PostMessageToConversation"
    }
  },
  "runAfter": {
    "backups": [
      "Succeeded"
    ]
  }
}

output_message.png

This simple setup brings three clear benefits: