@ericrisco/rsc 0.1.37 → 0.1.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/manifest.json +130 -4
- package/package.json +1 -1
- package/scripts/lib/domains.js +1 -0
- package/scripts/lib/recommend.js +5 -0
- package/skills/automation-flows/SKILL.md +1 -1
- package/skills/automation-strategy/SKILL.md +131 -0
- package/skills/automation-strategy/evals/README.md +16 -0
- package/skills/automation-strategy/evals/cases.yaml +48 -0
- package/skills/automation-strategy/references/automate-decision-and-roi.md +118 -0
- package/skills/automation-strategy/references/orchestration-and-antipatterns.md +107 -0
- package/skills/automation-strategy/references/platform-selection-matrix.md +86 -0
- package/skills/harness/references/providers.yaml +101 -0
- package/skills/make/SKILL.md +255 -0
- package/skills/make/evals/README.md +14 -0
- package/skills/make/evals/cases.yaml +45 -0
- package/skills/make/references/api-v2-cheatsheet.md +114 -0
- package/skills/make/references/blueprint-round-trip.md +128 -0
- package/skills/make/references/make-mcp-and-auth.md +101 -0
- package/skills/n8n/SKILL.md +205 -0
- package/skills/n8n/evals/README.md +14 -0
- package/skills/n8n/evals/cases.yaml +45 -0
- package/skills/n8n/references/auth-and-selfhost.md +62 -0
- package/skills/n8n/references/n8n-mcp-tools.md +84 -0
- package/skills/n8n/references/rest-api-cheatsheet.md +94 -0
- package/skills/power-automate/SKILL.md +169 -0
- package/skills/power-automate/evals/README.md +17 -0
- package/skills/power-automate/evals/cases.yaml +43 -0
- package/skills/power-automate/references/dataverse-web-api.md +187 -0
- package/skills/power-automate/references/entra-auth-setup.md +75 -0
- package/skills/power-automate/references/flowstudio-mcp-and-limits.md +62 -0
- package/skills/roast-me/tools/adapters/__pycache__/__init__.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/base.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/claude.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/codex.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/gemini.cpython-312.pyc +0 -0
- package/skills/roast-me/tools/adapters/__pycache__/registry.cpython-312.pyc +0 -0
- package/skills/zapier/SKILL.md +145 -0
- package/skills/zapier/evals/README.md +5 -0
- package/skills/zapier/evals/cases.yaml +50 -0
- package/skills/zapier/references/programmatic-limits-and-partner-api.md +48 -0
- package/skills/zapier/references/when-to-use-vs-n8n-make.md +44 -0
- package/skills/zapier/references/zapier-mcp-tools.md +72 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# n8n auth, self-host vs cloud, and pointing n8n-mcp
|
|
2
|
+
|
|
3
|
+
## Get an API key
|
|
4
|
+
|
|
5
|
+
1. In n8n, open **Settings → n8n API**.
|
|
6
|
+
2. **Create an API key.** Prefer a **scoped** key — pick only the resource scopes the automation needs
|
|
7
|
+
(e.g. `workflow:read`, `workflow:create`, `workflow:execute`, `execution:read`). An unscoped key can
|
|
8
|
+
do everything the user can, including delete.
|
|
9
|
+
3. Copy it once (it is shown once) and store it as `N8N_API_KEY`. Rotate by deleting + recreating.
|
|
10
|
+
|
|
11
|
+
Every REST call carries it as a header: `X-N8N-API-KEY: <key>`. It is NOT a bearer token and NOT in
|
|
12
|
+
the query string.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
export N8N_API_KEY="n8n_api_..."
|
|
16
|
+
export N8N_API_URL="https://your-instance.app.n8n.cloud" # host root; append /api/v1 for REST
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Self-host vs cloud — what actually differs
|
|
20
|
+
|
|
21
|
+
| | Self-host | Cloud (`*.app.n8n.cloud`) |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| API base | `{host}/api/v1` (e.g. `http://localhost:5678/api/v1`) | `https://<tenant>.app.n8n.cloud/api/v1` |
|
|
24
|
+
| API surface | **identical** | **identical** |
|
|
25
|
+
| Interactive Swagger | **Yes** at `/api/v1/docs` | **No** — work from docs.n8n.io |
|
|
26
|
+
| Where data lives | your infra | n8n's |
|
|
27
|
+
| Enabling the API | on by default; can be toggled via `N8N_PUBLIC_API_DISABLED=true` | always on |
|
|
28
|
+
| Base URL override | `WEBHOOK_URL` / `N8N_HOST`/`N8N_PROTOCOL`/`N8N_PORT` shape the host + webhook URLs | fixed |
|
|
29
|
+
|
|
30
|
+
The only thing that changes between environments is the host and (self-host) the Swagger page.
|
|
31
|
+
Scripts written against one work against the other by swapping `N8N_API_URL`.
|
|
32
|
+
|
|
33
|
+
Webhook URLs on self-host derive from `WEBHOOK_URL` (or host/protocol/port). If your production webhook
|
|
34
|
+
URLs look wrong (localhost behind a proxy), that env var is usually why.
|
|
35
|
+
|
|
36
|
+
## Pointing n8n-mcp at your instance
|
|
37
|
+
|
|
38
|
+
`n8n-mcp` reads the **same two env vars** for its management tier:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
N8N_API_URL=https://your-instance.app.n8n.cloud
|
|
42
|
+
N8N_API_KEY=n8n_api_...
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Ways to run it:
|
|
46
|
+
|
|
47
|
+
- **Hosted** — `dashboard.n8n-mcp.com`: add an instance (URL + key), get an MCP endpoint. Fastest trial;
|
|
48
|
+
free tier caps daily tool calls.
|
|
49
|
+
- **Local (npx)** — run the `n8n-mcp` package and register it in your MCP client's config
|
|
50
|
+
(Claude Code / Claude Desktop / Cursor / Windsurf), passing the two env vars.
|
|
51
|
+
- **Docker** — the repo ships an image; inject the env vars.
|
|
52
|
+
|
|
53
|
+
Node-knowledge tools work with **no** auth; only the management tools need the two vars. Confirm the
|
|
54
|
+
link with `n8n_health_check` — it reports reachability and which features (e.g. the `/execute`
|
|
55
|
+
endpoint) the target instance supports.
|
|
56
|
+
|
|
57
|
+
## Governance quick-set
|
|
58
|
+
|
|
59
|
+
- **Scope the key** at creation (least privilege) — see above.
|
|
60
|
+
- **`DISABLED_TOOLS`** on n8n-mcp to gate destructive tools — see `n8n-mcp-tools.md`.
|
|
61
|
+
- **Never** commit `N8N_API_KEY` or inline node-credential secrets in a workflow payload; reference
|
|
62
|
+
credentials from the n8n credential store by id/name.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# n8n-mcp — tool reference & governance
|
|
2
|
+
|
|
3
|
+
`n8n-mcp` (github.com/czlonkowski/n8n-mcp, ~22k★, the de-facto community standard) is an MCP server
|
|
4
|
+
that gives an agent two things: **offline knowledge** of n8n's node/expression catalogue, and
|
|
5
|
+
**management** of a live instance via its REST API. Distinct from n8n's own first-party built-in MCP
|
|
6
|
+
node, which lets a *workflow* act as an MCP server/client — that is not this.
|
|
7
|
+
|
|
8
|
+
Tool names and counts move; **verify against the running server's tool list** (or
|
|
9
|
+
`dashboard.n8n-mcp.com` / the repo docs) before relying on any one name.
|
|
10
|
+
|
|
11
|
+
## Two tiers, two auth requirements
|
|
12
|
+
|
|
13
|
+
| Tier | Needs auth? | Purpose |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| **Node-knowledge tools** | **No** | Search/describe nodes, get property essentials, validate a node's config, browse templates — all offline. Safe to expose broadly. |
|
|
16
|
+
| **Management tools** | **Yes** — `N8N_API_URL` + `N8N_API_KEY` | CRUD/validate/test/run/inspect a real instance. These are the ones governance applies to. |
|
|
17
|
+
|
|
18
|
+
Set the same two env vars the REST API uses:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
N8N_API_URL=https://your-instance.app.n8n.cloud # host root, whole value
|
|
22
|
+
N8N_API_KEY=n8n_api_...
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Without them the server still runs — you just get the node-knowledge tier only.
|
|
26
|
+
|
|
27
|
+
## Node-knowledge tools (no auth)
|
|
28
|
+
|
|
29
|
+
- `search_nodes`, `list_nodes`, `list_ai_tools` — find the right node.
|
|
30
|
+
- `get_node_essentials`, `get_node_info`, `get_node_documentation` — properties & docs for a node type.
|
|
31
|
+
- `validate_node_operation`, `validate_node_minimal` — check a single node's config before you wire it.
|
|
32
|
+
- `search_templates`, `get_template` — reuse community workflow templates.
|
|
33
|
+
|
|
34
|
+
Use these to author node JSON correctly instead of guessing `typeVersion`/property shapes.
|
|
35
|
+
|
|
36
|
+
## Management tools (need `N8N_API_URL` + `N8N_API_KEY`)
|
|
37
|
+
|
|
38
|
+
| Tool | Does |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `n8n_create_workflow` | Create from a full workflow object. |
|
|
41
|
+
| `n8n_get_workflow` | Fetch one workflow (export before delete/replace). |
|
|
42
|
+
| `n8n_list_workflows` | List/filter workflows. |
|
|
43
|
+
| `n8n_update_full_workflow` | Replace the whole workflow (like REST `PUT`). |
|
|
44
|
+
| `n8n_update_partial_workflow` | **Atomic ordered batch of targeted edits** — if any op fails, nothing is saved. Prefer this for edits. |
|
|
45
|
+
| `n8n_delete_workflow` | **Hard delete.** Export first. |
|
|
46
|
+
| `n8n_validate_workflow` | Structural/connection/expression validation of a workflow object. |
|
|
47
|
+
| `n8n_autofix_workflow` | Repair common errors and return fixed JSON. |
|
|
48
|
+
| `n8n_test_workflow` | Trigger a run for testing. |
|
|
49
|
+
| `n8n_executions` | List/inspect execution runs. |
|
|
50
|
+
| `n8n_workflow_versions` | Version history of a workflow. |
|
|
51
|
+
| `n8n_deploy_template` | Deploy a catalogue template to the instance. |
|
|
52
|
+
| `n8n_manage_credentials` | Create/manage credentials (secrets not readable back). |
|
|
53
|
+
| `n8n_manage_datatable` | Manage n8n data tables. |
|
|
54
|
+
| `n8n_health_check` | Confirm API reachability + which features the instance supports. |
|
|
55
|
+
| `n8n_audit_instance` | Security audit (built-in audit API + deep workflow scan). |
|
|
56
|
+
|
|
57
|
+
**Note on activate/deactivate:** n8n-mcp intentionally does not surface these as tools (activation has
|
|
58
|
+
live side effects). Flip a workflow live with the REST `POST /workflows/{id}/activate` endpoint (see
|
|
59
|
+
`rest-api-cheatsheet.md`) or the UI. Verify the current tool list in case this changes.
|
|
60
|
+
|
|
61
|
+
## Governance — `DISABLED_TOOLS`
|
|
62
|
+
|
|
63
|
+
For agent-facing deployments, disable destructive/write tools with a comma-separated env var:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# read-only agent: no create/replace/delete/autofix/test/template/credential/datatable writes
|
|
67
|
+
DISABLED_TOOLS=n8n_create_workflow,n8n_update_full_workflow,n8n_update_partial_workflow,n8n_delete_workflow,n8n_autofix_workflow,n8n_deploy_template,n8n_test_workflow,n8n_manage_credentials,n8n_manage_datatable
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Layer it with a **scoped API key** (grant only `workflow:read`/`execution:read` for a monitoring
|
|
71
|
+
agent) so a disabled tool can't be worked around and the key itself can't mutate. Two independent
|
|
72
|
+
locks: the tool gate and the key scope.
|
|
73
|
+
|
|
74
|
+
## Sketch: agent-driven deploy
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
search_nodes / get_node_essentials → get the exact node property shapes
|
|
78
|
+
n8n_validate_workflow { workflow } → catch structural errors offline
|
|
79
|
+
n8n_autofix_workflow { workflow } → auto-repair, re-validate
|
|
80
|
+
n8n_create_workflow { name, nodes, connections, settings } → capture returned id
|
|
81
|
+
n8n_test_workflow { id } → confirm it runs
|
|
82
|
+
# then activate via REST /workflows/{id}/activate (no MCP tool for it)
|
|
83
|
+
n8n_executions { workflowId: id } → confirm the live run
|
|
84
|
+
```
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# n8n public REST API — cheat sheet
|
|
2
|
+
|
|
3
|
+
Base URL: `{host}/api/v1`. Auth header on every call: `X-N8N-API-KEY: $N8N_API_KEY`.
|
|
4
|
+
Same surface on self-host and `*.app.n8n.cloud`. Self-host has interactive Swagger at
|
|
5
|
+
`{host}/api/v1/docs`; cloud does not. Verify shapes at author time — n8n ships often.
|
|
6
|
+
|
|
7
|
+
Set once:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
export N8N_API_URL="https://your-instance.app.n8n.cloud" # or http://localhost:5678
|
|
11
|
+
export N8N_API_KEY="n8n_api_..."
|
|
12
|
+
auth=(-H "X-N8N-API-KEY: $N8N_API_KEY")
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Workflows
|
|
16
|
+
|
|
17
|
+
| Verb & path | What it does | Notes |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `POST /workflows` | Create | Body needs `name, nodes, connections, settings`. `active` + `tags` in the body are **ignored** (read-only). Returns the new object incl. `id`. |
|
|
20
|
+
| `GET /workflows/{id}` | Get one | The full exportable JSON. Use to back up before delete/replace. |
|
|
21
|
+
| `GET /workflows` | List | Query: `limit` (default ~100), `cursor`, `active=true|false`, `tags`, `name`, `projectId`. Paginate with the returned `nextCursor`. |
|
|
22
|
+
| `PUT /workflows/{id}` | **Full replace** | Send the WHOLE object; omitted fields are dropped. GET → mutate → PUT. |
|
|
23
|
+
| `DELETE /workflows/{id}` | **Hard delete** | No trash, no undo. Export first. |
|
|
24
|
+
| `POST /workflows/{id}/activate` | Activate | The ONLY way to go live — the body `active` flag never does it. |
|
|
25
|
+
| `POST /workflows/{id}/deactivate` | Deactivate | Same, in reverse. |
|
|
26
|
+
| `POST /workflows/{id}/execute` | Run by id | **Recent (PR #20234); older instances 404.** Runs `executeManually`; **accepts no custom input** — needs `workflow:execute` scope. |
|
|
27
|
+
| `PUT /workflows/{id}/tags` | Set tags | Tags are managed here, not in the create/update body. |
|
|
28
|
+
| `PUT /workflows/{id}/transfer` | Move to a project | Enterprise/projects. |
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
curl -sS -X POST "$N8N_API_URL/api/v1/workflows" "${auth[@]}" \
|
|
32
|
+
-H "Content-Type: application/json" -d @workflow.json
|
|
33
|
+
curl -sS "$N8N_API_URL/api/v1/workflows?limit=50&active=true" "${auth[@]}"
|
|
34
|
+
curl -sS "$N8N_API_URL/api/v1/workflows/$ID" "${auth[@]}" > backup-$ID.json
|
|
35
|
+
curl -sS -X POST "$N8N_API_URL/api/v1/workflows/$ID/activate" "${auth[@]}"
|
|
36
|
+
curl -sS -X POST "$N8N_API_URL/api/v1/workflows/$ID/execute" "${auth[@]}"
|
|
37
|
+
curl -sS -X DELETE "$N8N_API_URL/api/v1/workflows/$ID" "${auth[@]}"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Paginate:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
cursor=""
|
|
44
|
+
while :; do
|
|
45
|
+
page=$(curl -sS "$N8N_API_URL/api/v1/workflows?limit=100&cursor=$cursor" "${auth[@]}")
|
|
46
|
+
echo "$page" | jq -r '.data[].id'
|
|
47
|
+
cursor=$(echo "$page" | jq -r '.nextCursor // empty')
|
|
48
|
+
[ -z "$cursor" ] && break
|
|
49
|
+
done
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Executions
|
|
53
|
+
|
|
54
|
+
| Verb & path | What it does |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `GET /executions` | List runs. Query: `workflowId`, `status` (`success|error|waiting`), `limit`, `cursor`, `includeData=true`. |
|
|
57
|
+
| `GET /executions/{id}` | One run; `?includeData=true` for the full item data. |
|
|
58
|
+
| `DELETE /executions/{id}` | Delete a run's stored data. |
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
curl -sS "$N8N_API_URL/api/v1/executions?workflowId=$ID&status=error&limit=20" "${auth[@]}"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Triggering a run WITH input
|
|
65
|
+
|
|
66
|
+
`/execute` takes no body data. To pass runtime params, the workflow's trigger must be a **Webhook**
|
|
67
|
+
node; POST to its URL:
|
|
68
|
+
|
|
69
|
+
- Test URL (only while the editor's "Listen for test event" is armed): `{host}/webhook-test/<path>`
|
|
70
|
+
- Production URL (only once the workflow is active): `{host}/webhook/<path>`
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
curl -sS -X POST "$N8N_HOST/webhook/my-path" -H "Content-Type: application/json" -d '{"orderId":123}'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Other resources
|
|
77
|
+
|
|
78
|
+
- `GET/POST/DELETE /credentials` — create/delete credentials and `GET /credentials/schema/{type}` for
|
|
79
|
+
the field shape. **You cannot read secrets back.** Reference existing creds from a workflow by id/name.
|
|
80
|
+
- `GET/POST/PUT/DELETE /tags`, `/projects`, `/variables`, `/users` (admin), `/source-control/pull`,
|
|
81
|
+
`/audit` (instance security audit).
|
|
82
|
+
|
|
83
|
+
## API-key scopes (least privilege)
|
|
84
|
+
|
|
85
|
+
Create a **scoped** key in Settings → n8n API. Scopes are grouped by resource, e.g. `workflow:read`,
|
|
86
|
+
`workflow:create`, `workflow:update`, `workflow:delete`, `workflow:execute`, `execution:read`,
|
|
87
|
+
`credential:create`, `tag:*`. Grant only what a given automation needs — e.g. a read-only dashboard
|
|
88
|
+
key gets `workflow:read` + `execution:read` and nothing that can mutate or run.
|
|
89
|
+
|
|
90
|
+
## Error responses
|
|
91
|
+
|
|
92
|
+
`401` bad/missing key · `403` key lacks the scope · `404` no such id (or `/execute` on an instance
|
|
93
|
+
too old to have it) · `400` malformed body (e.g. missing `connections`) · `500` server-side (often a
|
|
94
|
+
node the instance doesn't have installed).
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: power-automate
|
|
3
|
+
description: "Use when operating Microsoft Power Automate cloud flows programmatically — creating, enabling, updating, listing or deleting flows through the Dataverse Web API (the workflow table, category 5) with Entra ID / OAuth2 auth, or reading action-level run history via the third-party FlowStudio MCP. Triggers: 'create a Power Automate cloud flow with the Dataverse API', 'enable my flow by code / set statecode to 1', 'why can't I create or edit a My Flow programmatically', 'PATCH the workflow clientdata', 'automatizar el despliegue de un flujo de Power Automate desde código'. NOT designing the flow or authoring its definition (automation-flows), NOT choosing a platform by billing model (automation-strategy), NOT a generic typed REST client with auth/pagination/backoff (api-connector-builder), NOT the endpoint receiving an HTTP-trigger POST in your app (webhooks), NOT scripting Microsoft 365 / Graph mail & calendar directly (no first-party skill — api-connector-builder, or google-workspace)."
|
|
4
|
+
tags: [power-automate, dataverse, microsoft, flows, entra, oauth, mcp, m365, automation]
|
|
5
|
+
recommends: [automation-flows, automation-strategy, api-connector-builder, webhooks]
|
|
6
|
+
profiles: [full]
|
|
7
|
+
origin: risco
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Power Automate — operate cloud flows through Dataverse, honestly
|
|
11
|
+
|
|
12
|
+
Drive Microsoft Power Automate **cloud flows** from code: create, enable, update, list, and delete them, plus pull run history for debugging. This skill operates the *live* surface. Deciding what the flow should do and shaping its trigger→actions→error definition is design — that lives in `../automation-flows/SKILL.md`; this skill wraps that definition, ships it, and manages it.
|
|
13
|
+
|
|
14
|
+
Read these three facts before you write a line — they set the boundary of what is even possible:
|
|
15
|
+
|
|
16
|
+
1. **Only flows inside a Dataverse *solution* are code-manageable.** Classic personal **"My Flows"** cannot be created or edited by code — the Microsoft docs say so explicitly. If the target is a My Flow, the honest answer is: move it into a solution first, or drive it by hand. There is no API workaround.
|
|
17
|
+
2. **`api.flow.microsoft.com` is unsupported.** Microsoft's own words: use it "at your own risk," it is subject to breaking changes. The supported programmatic surface is the **Dataverse Web API** (or the .NET SDK) against the `workflow` table. For admin-style operations the **Power Automate Management** connector is the other supported path.
|
|
18
|
+
3. **The unified Power Platform API (`api.powerplatform.com`) is maturing fast.** It already lists cloud flows (api-version `2024-10-01`) and its Inventory API went GA in early 2026. It may eventually supersede the Dataverse path for flow management. Treat the Dataverse-vs-Power-Platform-API split as fast-moving — verify the current recommendation at author time.
|
|
19
|
+
|
|
20
|
+
## Connect first — API vs MCP
|
|
21
|
+
|
|
22
|
+
Everything runs against your org's Dataverse Web API. **Base URL:** `https://{org}.{region}.dynamics.com/api/data/v9.2` (find yours under Power Platform admin → your environment → developer resources). Auth is **OAuth2 / Entra ID** — a user token or, for CI, a **service principal** (app registration). For a service principal the org needs a **Dataverse application user** mapped to that app plus a security role; the token audience is the Dataverse URL. Full setup, including the delegated `user_impersonation` vs app `.default` scope split and the 401/403 causes, is in `references/entra-auth-setup.md`.
|
|
23
|
+
|
|
24
|
+
Put these in `.env` (never inline a secret in a flow or a script):
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
PA_DATAVERSE_URL=https://contoso.crm.dynamics.com # no trailing slash, no /api/...
|
|
28
|
+
PA_TENANT_ID=<entra-tenant-guid>
|
|
29
|
+
PA_CLIENT_ID=<app-registration-client-id>
|
|
30
|
+
PA_CLIENT_SECRET=<app-registration-secret> # service-principal flow only
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**When to use the REST API vs the MCP:**
|
|
34
|
+
|
|
35
|
+
| You need to… | Use | Why |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| Create / enable / update / delete / list flows | **Dataverse Web API** | The only supported CRUD surface; scriptable, CI-friendly, service-principal auth. |
|
|
38
|
+
| Read a flow's **action-level** run inputs/outputs to debug a failure | **FlowStudio MCP** (third-party) | Dataverse exposes run *records* (`flowrun` table) but not per-action I/O; the MCP does. See `references/flowstudio-mcp-and-limits.md`. |
|
|
39
|
+
| Admin-scope operations (turn on/off across an environment) | Power Automate **Management** connector | Supported management surface when raw Dataverse is awkward. |
|
|
40
|
+
|
|
41
|
+
**FlowStudio MCP is NOT Microsoft-affiliated** — it is a de-facto third-party server (`mcp.flowstudio.app/mcp`). Microsoft's own MCP story is Copilot Studio *consuming* MCP servers and a Dataverse MCP, neither of which authors Power Automate flows. Flag the third-party dependency to anyone before wiring it into a pipeline.
|
|
42
|
+
|
|
43
|
+
## The `workflow` table — the data model
|
|
44
|
+
|
|
45
|
+
Cloud flows are rows in the Dataverse **Process (`workflow`)** table. The columns that matter:
|
|
46
|
+
|
|
47
|
+
| Column | Meaning | Values you use |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `category` | Kind of process | **`5` = modern cloud flow** (automated / instant / scheduled). (0 classic workflow, 4 business process flow, 6 desktop flow.) |
|
|
50
|
+
| `type` | Definition vs template | **`1` = Definition** (a runnable flow). |
|
|
51
|
+
| `statecode` | On/off state | **`0` = Draft (Off)**, **`1` = Activated (On)**, `2` = Suspended. |
|
|
52
|
+
| `name` | Display name | your string |
|
|
53
|
+
| `primaryentity` | Bound table | **`"none"`** for automated/instant/scheduled flows |
|
|
54
|
+
| `clientdata` | The flow itself | **string-encoded JSON** (see below) |
|
|
55
|
+
| `workflowid` | GUID key | returned on create; used in `workflows({id})` |
|
|
56
|
+
|
|
57
|
+
List the cloud flows that are on:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
curl -s "$PA_DATAVERSE_URL/api/data/v9.2/workflows?\$filter=category eq 5 and statecode eq 1&\$select=name,statecode,type,workflowid" \
|
|
61
|
+
-H "Authorization: Bearer $TOKEN" -H "OData-Version: 4.0" -H "Accept: application/json"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## `clientdata` — the payload, and the trap that bites everyone
|
|
65
|
+
|
|
66
|
+
`clientdata` is **a JSON string, not a nested JSON object.** It is the serialized form of:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"properties": {
|
|
71
|
+
"connectionReferences": { "shared_commondataserviceforapps": { "runtimeSource": "embedded", "connection": {}, "api": { "name": "shared_commondataserviceforapps" } } },
|
|
72
|
+
"definition": { "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", "contentVersion": "1.0.0.0", "triggers": { }, "actions": { } }
|
|
73
|
+
},
|
|
74
|
+
"schemaVersion": "1.0.0.0"
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Two load-bearing parts:
|
|
79
|
+
|
|
80
|
+
- **`definition`** — a Logic Apps workflow definition: `triggers` (exactly one) then `actions`. This is the *design* artifact. Do not invent it from scratch here — get the trigger→actions→branch→error shape from `../automation-flows/SKILL.md`, then drop it into `definition`. Fastest reliable way to get a real one: build the flow once in the maker portal, export the solution, and copy its `clientdata`.
|
|
81
|
+
- **`connectionReferences`** — the map from the definition's connectors to actual connections. **A flow whose connection references are not authorized will not turn on.** In a solution these are connection-reference records the target environment must resolve; unresolved references are the #1 reason a `PATCH statecode=1` "succeeds" but the flow never runs.
|
|
82
|
+
|
|
83
|
+
**The trap:** `clientdata` must be *escaped into a string* before it goes in the request body — a nested object is rejected. In a script, `JSON.stringify(clientDataObject)` and assign the result; do not paste the object raw. Full annotated example in `references/dataverse-web-api.md`.
|
|
84
|
+
|
|
85
|
+
## Dynamic lifecycle — token → create → validate → enable → manage → delete
|
|
86
|
+
|
|
87
|
+
**1. Get a token** (service-principal / client-credentials shown):
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
TOKEN=$(curl -s -X POST "https://login.microsoftonline.com/$PA_TENANT_ID/oauth2/v2.0/token" \
|
|
91
|
+
-d "grant_type=client_credentials" -d "client_id=$PA_CLIENT_ID" \
|
|
92
|
+
-d "client_secret=$PA_CLIENT_SECRET" -d "scope=$PA_DATAVERSE_URL/.default" \
|
|
93
|
+
| python3 -c "import sys,json;print(json.load(sys.stdin)['access_token'])")
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**2. Create the flow** (comes up `statecode=0`, Off — expected):
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
curl -s -i -X POST "$PA_DATAVERSE_URL/api/data/v9.2/workflows" \
|
|
100
|
+
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
101
|
+
-H "OData-Version: 4.0" \
|
|
102
|
+
-d '{ "category": 5, "type": 1, "name": "Nightly sync", "primaryentity": "none", "clientdata": "<string-encoded JSON>" }'
|
|
103
|
+
# → 204 No Content. The workflowid is in the OData-EntityId response header:
|
|
104
|
+
# OData-EntityId: .../workflows(00aa00aa-bb11-cc22-dd33-44ee44ee44ee)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**3. Validate before enabling.** Read it back, confirm `category`/`type` are right, and confirm every `connectionReferences` entry resolves to an authorized connection in this environment. Enabling a flow with dangling connections is the classic silent failure.
|
|
108
|
+
|
|
109
|
+
**4. Enable** — flip `statecode` to `1` (use `If-Match: *` for the update):
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
curl -s -X PATCH "$PA_DATAVERSE_URL/api/data/v9.2/workflows(<workflowid>)" \
|
|
113
|
+
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
114
|
+
-H "OData-Version: 4.0" -H "If-Match: *" \
|
|
115
|
+
-d '{ "statecode": 1 }'
|
|
116
|
+
# → 204 No Content
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**5. Manage** — update the definition or owner with the same `PATCH` (send only the fields you change; to reassign use `"ownerid@odata.bind": "systemusers(<id>)"`). To turn a flow off, `PATCH statecode=0`.
|
|
120
|
+
|
|
121
|
+
**6. Delete — irreversible; export first.** There is no undo on `DELETE`. **Before deleting, export the containing solution** (`POST /api/data/v9.2/ExportSolution` → base64 zip you save to source control), so the flow can be reimported:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
curl -s -X DELETE "$PA_DATAVERSE_URL/api/data/v9.2/workflows(<workflowid>)" \
|
|
125
|
+
-H "Authorization: Bearer $TOKEN"
|
|
126
|
+
# → 204 No Content
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Debug a run** — Dataverse's `flowrun` table lists run records but not per-action I/O. To see *which action failed and with what payload*, use FlowStudio MCP: `list_live_flows` → `get_live_flow_runs` → `get_live_flow_run_action_outputs`. See `references/flowstudio-mcp-and-limits.md`.
|
|
130
|
+
|
|
131
|
+
## Microsoft 365 ecosystem fit
|
|
132
|
+
|
|
133
|
+
Power Automate is Microsoft's iPaaS across M365 and Dynamics; flows live in **Dataverse** and glue Outlook, Teams, SharePoint, Dynamics, and hundreds of connectors. That means the boundary is sharp: if the ask is *"send this email / read this calendar via Microsoft Graph from my own backend code,"* that is not a flow at all — build a typed Graph client with `../api-connector-builder/SKILL.md` (there is no first-party MS-Graph skill). If the equivalent is on Google, that is `../google-workspace/SKILL.md`. This skill is for when the automation genuinely *is* a Power Automate flow you must operate by code.
|
|
134
|
+
|
|
135
|
+
## Honesty / gotchas
|
|
136
|
+
|
|
137
|
+
| Trap | Why it bites | Do instead |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| Trying to CRUD a **My Flow** by code | Unsupported — silently impossible, not a bug you can fix | Move it into a Dataverse solution, or drive it by hand |
|
|
140
|
+
| `clientdata` sent as a nested object | Request rejected; the column expects an escaped **string** | Serialize (`JSON.stringify`) the definition+connectionReferences before sending |
|
|
141
|
+
| `PATCH statecode=1` "worked" but the flow never runs | Connection references unresolved/unauthorized in the target environment | Authorize every connection reference before enabling; validate on read-back |
|
|
142
|
+
| Building against `api.flow.microsoft.com` | Unsupported; breaks without warning | Dataverse Web API, or the Power Automate Management connector |
|
|
143
|
+
| `DELETE` with no export | No undo; the flow and its history are gone | `ExportSolution` first, save the zip, then delete |
|
|
144
|
+
| Hardcoding the Dataverse URL / secret | Env-specific, leaks in source | `.env`: `PA_DATAVERSE_URL`, `PA_TENANT_ID`, `PA_CLIENT_ID`, `PA_CLIENT_SECRET` |
|
|
145
|
+
| Assuming the Dataverse path is permanent | Power Platform API is superseding surfaces piecemeal | Re-check `api.powerplatform.com` coverage at author time; the split is fast-moving |
|
|
146
|
+
|
|
147
|
+
## Related skills
|
|
148
|
+
|
|
149
|
+
- **`../automation-flows/SKILL.md`** — design side: what the trigger→actions→branch→error should be, the importable definition. This skill *consumes* that shape as `clientdata.definition`. Design there, operate here.
|
|
150
|
+
- **`../automation-strategy/SKILL.md`** — choosing Power Automate vs n8n/Make/Zapier by billing and constraints. Decide there before you commit to operating here.
|
|
151
|
+
- **`../api-connector-builder/SKILL.md`** — a generic typed REST client with auth/pagination/backoff (including a Dataverse or MS Graph client). This skill uses the Dataverse API surgically; it does not build a general client.
|
|
152
|
+
- **`../webhooks/SKILL.md`** — building the inbound endpoint in *your* app that receives a flow's HTTP-trigger POST. This skill triggers/operates flows; it does not build the receiver.
|
|
153
|
+
|
|
154
|
+
## Checklist
|
|
155
|
+
|
|
156
|
+
- [ ] `.env` set: `PA_DATAVERSE_URL` (no trailing slash), `PA_TENANT_ID`, `PA_CLIENT_ID`, `PA_CLIENT_SECRET`.
|
|
157
|
+
- [ ] Confirmed the target is a **solution-aware** flow, not a My Flow.
|
|
158
|
+
- [ ] Token acquired against scope `{PA_DATAVERSE_URL}/.default` (or delegated `user_impersonation`).
|
|
159
|
+
- [ ] Create payload has `category:5`, `type:1`, `primaryentity:"none"`, and `clientdata` as an **escaped string**.
|
|
160
|
+
- [ ] Every `connectionReferences` entry maps to an authorized connection before enabling.
|
|
161
|
+
- [ ] Flow enabled via `PATCH statecode=1` and verified on read-back.
|
|
162
|
+
- [ ] Solution **exported** before any `DELETE`.
|
|
163
|
+
- [ ] No secrets or org URLs hardcoded; FlowStudio MCP (if used) flagged as third-party.
|
|
164
|
+
|
|
165
|
+
## References
|
|
166
|
+
|
|
167
|
+
- `references/dataverse-web-api.md` — endpoint cheat-sheet (token, list/filter, create, enable, update, delete, ExportSolution, share), the full annotated `clientdata`, OData headers, and error handling.
|
|
168
|
+
- `references/entra-auth-setup.md` — app registration, service principal vs delegated user, the Dataverse application user + security role, `.default` vs `user_impersonation`, and common 401/403 causes.
|
|
169
|
+
- `references/flowstudio-mcp-and-limits.md` — FlowStudio MCP tools and auth (third-party), what it exposes that Dataverse doesn't, and the platform limits (My Flows, `api.flow.microsoft.com`, Power Platform API evolution).
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Evals — power-automate
|
|
2
|
+
|
|
3
|
+
`cases.yaml` has three groups. `should_trigger` covers the programmatic operate cases: create+enable
|
|
4
|
+
via the Dataverse Web API, the My-Flows honesty question, enable-via-statecode, a Spanish
|
|
5
|
+
solution-aware CI deploy, FlowStudio-MCP run debugging, and a clientdata update. `should_not_trigger`
|
|
6
|
+
lists adjacent prompts owned by a named sibling — flow *design*/definition (automation-flows),
|
|
7
|
+
platform selection by billing (automation-strategy), generic typed-client engineering
|
|
8
|
+
(api-connector-builder), the inbound webhook receiver (webhooks), and direct Microsoft Graph
|
|
9
|
+
scripting (api-connector-builder, no first-party MS-Graph skill). `capability` is one end-to-end
|
|
10
|
+
lifecycle scenario whose `must_include` rubric checks the concrete API calls (token, POST, PATCH
|
|
11
|
+
statecode, DELETE), the string-encoded `clientdata`, the My-Flows/`api.flow.microsoft.com` honesty
|
|
12
|
+
limits, the ExportSolution-before-DELETE irreversibility rule, and the third-party FlowStudio-MCP
|
|
13
|
+
flag.
|
|
14
|
+
|
|
15
|
+
No automated runner. Score by judgement: feed each `should_trigger` / `should_not_trigger` prompt to
|
|
16
|
+
the routing layer and confirm it activates (or routes to the listed sibling); for `capability`, have
|
|
17
|
+
the skill produce the lifecycle walkthrough and check every `must_include` bullet by hand.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
skill: power-automate
|
|
2
|
+
|
|
3
|
+
should_trigger:
|
|
4
|
+
- prompt: "Create a Power Automate cloud flow via the Dataverse Web API and turn it on from my deploy script."
|
|
5
|
+
why: Canonical programmatic operate — POST /workflows (category 5) then enable via statecode; the core deliverable.
|
|
6
|
+
- prompt: "Why can't I edit my flow under 'My Flows' with the API? Every call I make fails."
|
|
7
|
+
why: The load-bearing honesty limit — My Flows are not code-manageable; must route to the solution-aware answer.
|
|
8
|
+
- prompt: "Enable my Power Automate flow by code — set statecode to 1 after I create it."
|
|
9
|
+
why: Enable-via-statecode is the explicit lifecycle step new flows come up Off (0) and need PATCH to 1.
|
|
10
|
+
- prompt: "Automatizar el despliegue de un flujo de Power Automate dentro de una solución de Dataverse desde CI."
|
|
11
|
+
why: Spanish; solution-aware programmatic deployment with a service principal — squarely this skill.
|
|
12
|
+
- prompt: "Use FlowStudio MCP to pull the action-level inputs and outputs of my flow's last failed run."
|
|
13
|
+
why: MCP run-history debugging that the Dataverse API doesn't expose per action — the MCP path this skill owns.
|
|
14
|
+
- prompt: "PATCH the clientdata of an existing workflow row to update the flow's definition."
|
|
15
|
+
why: Update lifecycle against the workflow table, including the clientdata string-encoding concern.
|
|
16
|
+
|
|
17
|
+
should_not_trigger:
|
|
18
|
+
- prompt: "Design a 'new Stripe payment → post to Teams' automation and give me the importable definition."
|
|
19
|
+
route_to: automation-flows
|
|
20
|
+
why: Designing what the flow does and authoring its definition is the design skill; this one operates a definition, it doesn't invent it.
|
|
21
|
+
- prompt: "Should I use Power Automate or n8n for about 50k runs a month?"
|
|
22
|
+
route_to: automation-strategy
|
|
23
|
+
why: Platform selection by billing/constraints, not operating a live Power Automate flow.
|
|
24
|
+
- prompt: "Write a typed TypeScript client for the Dataverse Web API with token refresh, pagination, and exponential backoff."
|
|
25
|
+
route_to: api-connector-builder
|
|
26
|
+
why: Generic client engineering (auth/pagination/retry) even though the API is Dataverse; this skill uses endpoints surgically, it doesn't build the client.
|
|
27
|
+
- prompt: "Build the Express endpoint that receives my flow's HTTP-trigger POST and verifies it."
|
|
28
|
+
route_to: webhooks
|
|
29
|
+
why: Building the inbound receiver in your own app; this skill operates/triggers flows, it does not build the receiver.
|
|
30
|
+
- prompt: "Send an email and read a calendar via Microsoft Graph from my Node backend."
|
|
31
|
+
route_to: api-connector-builder
|
|
32
|
+
why: Scripting Microsoft 365 via Graph directly is not a Power Automate flow; no first-party MS-Graph skill, so build a typed Graph client.
|
|
33
|
+
|
|
34
|
+
capability:
|
|
35
|
+
- scenario: "User has an Entra app registration and wants to create an automated cloud flow inside a Dataverse solution, enable it, later update its definition, and finally remove it safely. Walk the full programmatic lifecycle."
|
|
36
|
+
must_include:
|
|
37
|
+
- "Acquire an Entra OAuth2 token from https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token (client_credentials) with scope {PA_DATAVERSE_URL}/.default."
|
|
38
|
+
- "POST /api/data/v9.2/workflows with category=5, type=1, primaryentity=\"none\", name, and clientdata as a STRING-encoded JSON (definition + connectionReferences), not a nested object."
|
|
39
|
+
- "State the honesty limit: only flows inside a Dataverse solution are code-manageable; classic My Flows cannot be created or edited by code."
|
|
40
|
+
- "New flow comes up statecode=0 (Off); enable with PATCH workflows({workflowid}) statecode=1 using If-Match: *; validate connection references resolve before enabling."
|
|
41
|
+
- "Update via PATCH (send only changed fields), and note api.flow.microsoft.com is unsupported — use the Dataverse Web API or the Power Automate Management connector; flag api.powerplatform.com as an evolving alternative."
|
|
42
|
+
- "Irreversibility rule: ExportSolution to a saved base64 zip BEFORE DELETE workflows({workflowid}) — deletion has no undo."
|
|
43
|
+
- "For action-level run debugging use the third-party FlowStudio MCP (get_live_flow_run_action_outputs), flagged as NOT Microsoft-affiliated."
|