Skip to content

Commit d13c208

Browse files
ninihen1claude
andcommitted
fix: sync top-level source skills with plugin copies
Top-level source skills were stale — plugin copies had all the fixes (store tool removal from debug, list_live_flows in build, governance and monitoring updates) but the source skills were not updated. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3479f68 commit d13c208

4 files changed

Lines changed: 118 additions & 77 deletions

File tree

  • skills
    • flowstudio-power-automate-build
    • flowstudio-power-automate-debug
    • flowstudio-power-automate-governance
    • flowstudio-power-automate-monitoring

skills/flowstudio-power-automate-build/SKILL.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,15 @@ ENV = "<environment-id>" # e.g. Default-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
7373
Always look before you build to avoid duplicates:
7474

7575
```python
76-
results = mcp("list_store_flows",
77-
environmentName=ENV, searchTerm="My New Flow")
76+
results = mcp("list_live_flows", environmentName=ENV)
7877

79-
# list_store_flows returns a direct array (no wrapper object)
80-
if len(results) > 0:
78+
# list_live_flows returns { "flows": [...] }
79+
matches = [f for f in results["flows"]
80+
if "My New Flow".lower() in f["displayName"].lower()]
81+
82+
if len(matches) > 0:
8183
# Flow exists — modify rather than create
82-
# id format is "<environmentId>.<flowId>" — split to get the flow UUID
83-
FLOW_ID = results[0]["id"].split(".", 1)[1]
84+
FLOW_ID = matches[0]["id"] # plain UUID from list_live_flows
8485
print(f"Existing flow: {FLOW_ID}")
8586
defn = mcp("get_live_flow", environmentName=ENV, flowName=FLOW_ID)
8687
else:
@@ -402,7 +403,7 @@ if run["status"] == "Failed":
402403
root = err["failedActions"][-1]
403404
print(f"Root cause: {root['actionName']}{root.get('code')}")
404405
# Debug and fix the definition before proceeding
405-
# See power-automate-debug skill for full diagnosis workflow
406+
# See flowstudio-power-automate-debug skill for full diagnosis workflow
406407
```
407408
408409
#### 7c — Swap to the production trigger

skills/flowstudio-power-automate-debug/SKILL.md

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -72,46 +72,6 @@ ENV = "<environment-id>" # e.g. Default-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
7272

7373
---
7474

75-
## FlowStudio for Teams: Fast-Path Diagnosis (Skip Steps 2–4)
76-
77-
If you have a FlowStudio for Teams subscription, `get_store_flow_errors`
78-
returns per-run failure data including action names and remediation hints
79-
in a single call — no need to walk through live API steps.
80-
81-
```python
82-
# Quick failure summary
83-
summary = mcp("get_store_flow_summary", environmentName=ENV, flowName=FLOW_ID)
84-
# {"totalRuns": 100, "failRuns": 10, "failRate": 0.1,
85-
# "averageDurationSeconds": 29.4, "maxDurationSeconds": 158.9,
86-
# "firstFailRunRemediation": "<hint or null>"}
87-
print(f"Fail rate: {summary['failRate']:.0%} over {summary['totalRuns']} runs")
88-
89-
# Per-run error details (requires active monitoring to be configured)
90-
errors = mcp("get_store_flow_errors", environmentName=ENV, flowName=FLOW_ID)
91-
if errors:
92-
for r in errors[:3]:
93-
print(r["startTime"], "|", r.get("failedActions"), "|", r.get("remediationHint"))
94-
# If errors confirms the failing action → jump to Step 6 (apply fix)
95-
else:
96-
# Store doesn't have run-level detail for this flow — use live tools (Steps 2–5)
97-
pass
98-
```
99-
100-
For the full governance record (description, complexity, tier, connector list):
101-
```python
102-
record = mcp("get_store_flow", environmentName=ENV, flowName=FLOW_ID)
103-
# {"displayName": "My Flow", "state": "Started",
104-
# "runPeriodTotal": 100, "runPeriodFailRate": 0.1, "runPeriodFails": 10,
105-
# "runPeriodDurationAverage": 29410.8, ← milliseconds
106-
# "runError": "{\"code\": \"EACCES\", ...}", ← JSON string, parse it
107-
# "description": "...", "tier": "Premium", "complexity": "{...}"}
108-
if record.get("runError"):
109-
last_err = json.loads(record["runError"])
110-
print("Last run error:", last_err)
111-
```
112-
113-
---
114-
11575
## Step 1 — Locate the Flow
11676

11777
```python

skills/flowstudio-power-automate-governance/SKILL.md

Lines changed: 102 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,31 @@ environmentName = "Default-<envGuid>" (everything before first ".")
4848
flowName = "<flowGuid>" (everything after first ".")
4949
```
5050

51-
Also: skip entries from `list_store_flows` that have no `displayName`
52-
these are sparse/orphaned records.
51+
Also: skip entries that have no `displayName` or have `state=Deleted`
52+
these are sparse records or flows that no longer exist in Power Automate.
53+
If a deleted flow has `monitor=true`, suggest disabling monitoring
54+
(`update_store_flow` with `monitor=false`) to free up a monitoring slot
55+
(standard plan includes 20).
5356

5457
---
5558

5659
## The Write Tool: `update_store_flow`
5760

58-
`update_store_flow` is the only tool that writes governance metadata. It uses
59-
merge semantics — only fields you provide are updated. Returns the full
61+
`update_store_flow` writes governance metadata to the **Flow Studio cache
62+
only** — it does NOT modify the flow in Power Automate. These fields are
63+
not visible via `get_live_flow` or the PA portal. They exist only in the
64+
Flow Studio store and are used by Flow Studio's scanning pipeline and
65+
notification rules.
66+
67+
This means:
68+
- `ownerTeam` / `supportEmail` — sets who Flow Studio considers the
69+
governance contact. Does NOT change the actual PA flow owner.
70+
- `rule_notify_email` — sets who receives Flow Studio failure/missing-run
71+
notifications. Does NOT change Microsoft's built-in flow failure alerts.
72+
- `monitor` / `critical` / `businessImpact` — Flow Studio classification
73+
only. Power Automate has no equivalent fields.
74+
75+
Merge semantics — only fields you provide are updated. Returns the full
6076
updated record (same shape as `get_store_flow`).
6177

6278
Required parameters: `environmentName`, `flowName`. All other fields optional.
@@ -100,7 +116,7 @@ the CoE Starter Kit's Developer Compliance Center.
100116
1. Ask the user which compliance fields they require
101117
(or use their organization's existing governance policy)
102118
2. list_store_flows
103-
3. For each flow (skip entries without displayName):
119+
3. For each flow (skip entries without displayName or state=Deleted):
104120
- Split id → environmentName, flowName
105121
- get_store_flow(environmentName, flowName)
106122
- Check which required fields are missing or empty
@@ -127,6 +143,10 @@ the CoE Starter Kit's Developer Compliance Center.
127143
> suggestions based on common Power Platform governance patterns (CoE Starter
128144
> Kit). Ask the user what their requirements are before flagging flows as
129145
> non-compliant.
146+
>
147+
> **Tip:** Flows created or updated via MCP already have `description`
148+
> (auto-appended by `update_live_flow`). Flows created manually in the
149+
> Power Automate portal are the ones most likely missing governance metadata.
130150
131151
### 2. Orphaned Resource Detection
132152

@@ -137,7 +157,7 @@ Find flows owned by deleted or disabled Azure AD accounts.
137157
2. Filter where deleted=true AND ownerFlowCount > 0
138158
Note: deleted makers have NO displayName/mail — record their id (AAD OID)
139159
3. list_store_flows → collect all flows
140-
4. For each flow (skip entries without displayName):
160+
4. For each flow (skip entries without displayName or state=Deleted):
141161
- Split id → environmentName, flowName
142162
- get_store_flow(environmentName, flowName)
143163
- Parse owners: json.loads(record["owners"])
@@ -153,6 +173,14 @@ Find flows owned by deleted or disabled Azure AD accounts.
153173
> `update_store_flow` updates governance metadata in the cache only. To
154174
> transfer actual PA ownership, an admin must use the Power Platform admin
155175
> center or PowerShell.
176+
>
177+
> **Note:** Many orphaned flows are system-generated (created by
178+
> `DataverseSystemUser` accounts for SLA monitoring, knowledge articles,
179+
> etc.). These were never built by a person — consider tagging them
180+
> rather than reassigning.
181+
>
182+
> **Coverage:** This workflow searches the cached store only, not the
183+
> live PA API. Flows created after the last scan won't appear.
156184
157185
### 3. Archive Score Calculation
158186

@@ -161,7 +189,7 @@ candidates. Aligns with the CoE Starter Kit's archive scoring.
161189

162190
```
163191
1. list_store_flows
164-
2. For each flow (skip entries without displayName):
192+
2. For each flow (skip entries without displayName or state=Deleted):
165193
- Split id → environmentName, flowName
166194
- get_store_flow(environmentName, flowName)
167195
3. Compute archive score (0-7), add 1 point for each:
@@ -185,14 +213,21 @@ candidates. Aligns with the CoE Starter Kit's archive scoring.
185213
update_store_flow(environmentName, flowName, tags="<existing> #archived")
186214
```
187215

216+
> **What "archive" means:** Power Automate has no native archive feature.
217+
> Archiving via MCP means: (1) stop the flow so it can't run, and
218+
> (2) tag it `#archived` so it's discoverable for future cleanup.
219+
> Actual deletion requires the Power Automate portal or admin PowerShell
220+
> — it cannot be done via MCP tools.
221+
188222
### 4. Connector Audit
189223

190-
Audit which connectors are in use across the tenant. Useful for DLP impact
191-
analysis and premium license planning.
224+
Audit which connectors are in use across monitored flows. Useful for DLP
225+
impact analysis and premium license planning.
192226

193227
```
194-
1. list_store_flows
195-
2. For each flow (skip entries without displayName):
228+
1. list_store_flows(monitor=true)
229+
(scope to monitored flows — auditing all 1000+ flows is expensive)
230+
2. For each flow (skip entries without displayName or state=Deleted):
196231
- Split id → environmentName, flowName
197232
- get_store_flow(environmentName, flowName)
198233
- Parse connections: json.loads(record["connections"])
@@ -208,6 +243,15 @@ analysis and premium license planning.
208243
agent cross-references against the inventory
209244
```
210245

246+
> **Scope to monitored flows.** Each flow requires a `get_store_flow` call
247+
> to read the `connections` JSON. Standard plans have ~20 monitored flows —
248+
> manageable. Auditing all flows in a large tenant (1000+) would be very
249+
> expensive in API calls.
250+
>
251+
> **`list_store_connections`** returns connection instances (who created
252+
> which connection) but NOT connector types per flow. Use it for connection
253+
> counts per environment, not for the connector audit.
254+
>
211255
> DLP policy definitions are not available via MCP. The agent builds the
212256
> connector inventory; the user provides the DLP classification to
213257
> cross-reference against.
@@ -219,17 +263,21 @@ Configure monitoring and alerting for flows at scale.
219263
```
220264
Enable failure alerts on all critical flows:
221265
1. list_store_flows(monitor=true)
222-
2. For each flow (skip entries without displayName):
266+
2. For each flow (skip entries without displayName or state=Deleted):
223267
- Split id → environmentName, flowName
224268
- get_store_flow(environmentName, flowName)
225269
- If critical=true AND rule_notify_onfail is not true:
226270
update_store_flow(environmentName, flowName,
227271
rule_notify_onfail=true,
228272
rule_notify_email="oncall@contoso.com")
273+
- If NO flows have critical=true: this is a governance finding.
274+
Recommend the user designate their most important flows as critical
275+
using update_store_flow(critical=true) before configuring alerts.
229276
230277
Enable missing-run detection for scheduled flows:
231278
1. list_store_flows(monitor=true)
232279
2. For each flow where triggerType="Recurrence" (available on list response):
280+
- Skip flows with state="Stopped" or "Suspended" (not expected to run)
233281
- Split id → environmentName, flowName
234282
- get_store_flow(environmentName, flowName)
235283
- If rule_notify_onmissingdays is 0 or not set:
@@ -253,7 +301,7 @@ Bulk-classify flows by connector type, business function, or risk level.
253301
```
254302
Auto-tag by connector:
255303
1. list_store_flows
256-
2. For each flow (skip entries without displayName):
304+
2. For each flow (skip entries without displayName or state=Deleted):
257305
- Split id → environmentName, flowName
258306
- get_store_flow(environmentName, flowName)
259307
- Parse connections: json.loads(record["connections"])
@@ -268,23 +316,31 @@ Auto-tag by connector:
268316
tags="<existing tags> #sharepoint #teams")
269317
```
270318

271-
> **Tag merge:** `update_store_flow(tags=...)` overwrites the entire tags
272-
> field. To avoid losing tags from other workflows, always read the current
273-
> tags first, append new ones, then write back.
319+
> **Two tag systems:** Tags shown in `list_store_flows` are auto-extracted
320+
> from the flow's `description` field (e.g. a maker writes `#operations` in
321+
> the PA portal description). Tags set via `update_store_flow(tags=...)`
322+
> write to a separate field in the Azure Table cache. They are independent —
323+
> writing store tags does not touch the description, and editing the
324+
> description in the portal does not affect store tags.
325+
>
326+
> **Tag merge:** `update_store_flow(tags=...)` overwrites the store tags
327+
> field. To avoid losing tags from other workflows, read the current store
328+
> tags from `get_store_flow` first, append new ones, then write back.
274329
>
275330
> `get_store_flow` already has a `tier` field (Standard/Premium) computed
276331
> by the scanning pipeline. Only use `update_store_flow(tier=...)` if you
277332
> need to override it.
278333
279334
### 7. Maker Offboarding
280335

281-
When an employee leaves, identify and reassign their flows and apps.
336+
When an employee leaves, identify their flows and apps, and reassign
337+
Flow Studio governance contacts and notification recipients.
282338

283339
```
284340
1. get_store_maker(makerKey="<departing-user-aad-oid>")
285341
→ check ownerFlowCount, ownerAppCount, deleted status
286342
2. list_store_flows → collect all flows
287-
3. For each flow (skip entries without displayName):
343+
3. For each flow (skip entries without displayName or state=Deleted):
288344
- Split id → environmentName, flowName
289345
- get_store_flow(environmentName, flowName)
290346
- Parse owners: json.loads(record["owners"])
@@ -302,39 +358,57 @@ When an employee leaves, identify and reassign their flows and apps.
302358
6. Report: flows reassigned, flows stopped, apps needing manual reassignment
303359
```
304360

361+
> **What "reassign" means here:** `update_store_flow` changes who Flow
362+
> Studio considers the governance contact and who receives Flow Studio
363+
> notifications. It does NOT transfer the actual Power Automate flow
364+
> ownership — that requires the Power Platform admin center or PowerShell.
365+
> Also update `rule_notify_email` so failure notifications go to the new
366+
> team instead of the departing employee's email.
367+
>
305368
> Power Apps ownership cannot be changed via MCP tools. Report them for
306369
> manual reassignment in the Power Apps admin center.
307370
308371
### 8. Security Review
309372

310-
Identify flows with potential security concerns.
373+
Review flows for potential security concerns using cached store data.
311374

312375
```
313-
1. list_store_flows
314-
2. For each flow (skip entries without displayName):
376+
1. list_store_flows(monitor=true)
377+
2. For each flow (skip entries without displayName or state=Deleted):
315378
- Split id → environmentName, flowName
316379
- get_store_flow(environmentName, flowName)
317380
- Parse security: json.loads(record["security"])
318381
- Parse connections: json.loads(record["connections"])
319382
- Read sharingType directly (top-level field, NOT inside security JSON)
320-
3. Flag flows where:
321-
- security.triggerRequestAuthenticationType = "All"
322-
(no auth on HTTP trigger — open to internet)
323-
- sharingType = "Coauthor" (shared with co-authors, broader access)
324-
- connections contain HTTP connector (arbitrary outbound requests)
325-
- json.loads(referencedResources) points to external URLs
383+
3. Report findings to user for review
326384
4. For reviewed flows:
327385
Read existing tags, append #security-reviewed
328386
update_store_flow(environmentName, flowName, tags="<existing> #security-reviewed")
329387
Do NOT overwrite the security field — it contains structured auth data
330388
```
331389

390+
**Fields available for security review:**
391+
392+
| Field | Where | What it tells you |
393+
|---|---|---|
394+
| `security.triggerRequestAuthenticationType` | security JSON | `"All"` = HTTP trigger accepts unauthenticated requests |
395+
| `sharingType` | top-level | `"Coauthor"` = shared with co-authors for editing |
396+
| `connections` | connections JSON | Which connectors the flow uses (check for HTTP, custom) |
397+
| `referencedResources` | JSON string | SharePoint sites, Teams channels, external URLs the flow accesses |
398+
| `tier` | top-level | `"Premium"` = uses premium connectors |
399+
400+
> Each organization decides what constitutes a security concern. For example,
401+
> an unauthenticated HTTP trigger is expected for webhook receivers (Stripe,
402+
> GitHub) but may be a risk for internal flows. Review findings in context
403+
> before flagging.
404+
332405
### 9. Environment Governance
333406

334407
Audit environments for compliance and sprawl.
335408

336409
```
337410
1. list_store_environments
411+
Skip entries without displayName (tenant-level metadata rows)
338412
2. Flag:
339413
- Developer environments (sku="Developer") — should be limited
340414
- Non-managed environments (isManagedEnvironment=false) — less governance
@@ -405,7 +479,7 @@ Fields marked with `*` are also available on `list_store_flows` (cheaper).
405479
| `rule_notify_onmissingdays` | number | SLA monitoring configured? |
406480
| `rule_notify_email` | string | Alert recipients |
407481
| `description` | string | Documentation completeness |
408-
| `tags` * | string | Classification (overwrite semantics — read-merge-write to append) |
482+
| `tags` | string | Classification `list_store_flows` shows description-extracted hashtags only; store tags written by `update_store_flow` require `get_store_flow` to read back |
409483
| `runPeriodTotal` * | number | Activity level |
410484
| `runPeriodFailRate` * | number | Health status |
411485
| `runLast` | ISO string | Last run timestamp |

skills/flowstudio-power-automate-monitoring/SKILL.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ a flow was last scanned. If stale, the scanning pipeline may not be running.
5757
Flow Studio for Teams app
5858
([how to select flows](https://learn.flowstudio.app/teams-monitoring)).
5959

60+
**Designating critical flows:** Use `update_store_flow` with `critical=true`
61+
on business-critical flows. This enables the governance skill's notification
62+
rule management to auto-configure failure alerts on critical flows.
63+
6064
---
6165

6266
## Tools
@@ -132,8 +136,10 @@ Direct array. Filters: `monitor` (bool), `rule_notify_onfail` (bool),
132136
> `triggerUrl` and `tags` are optional. Some entries are sparse (just `id` +
133137
> `monitor`) — skip entries without `displayName`.
134138
>
135-
> Tags are auto-extracted from the `description` field using `#hashtag`
136-
> format. Can also be set explicitly via `update_store_flow`.
139+
> Tags on `list_store_flows` are auto-extracted from the flow's `description`
140+
> field (maker hashtags like `#operations`). Tags written via
141+
> `update_store_flow(tags=...)` are stored separately and only visible on
142+
> `get_store_flow` — they do NOT appear in the list response.
137143
138144
### `get_store_flow`
139145

0 commit comments

Comments
 (0)