@postman/postman-plugin 0.1.1-rc.0 → 0.1.2

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.
Files changed (40) hide show
  1. package/README.md +14 -2
  2. package/dist/cli.js +7 -1
  3. package/dist/hosts/index.js +2 -1
  4. package/dist/hosts/kimi.js +5 -2
  5. package/dist/hosts/pi.js +84 -0
  6. package/dist/pi-extension.js +27 -0
  7. package/dist/run.js +16 -10
  8. package/dist/source.js +3 -1
  9. package/hooks/session-start-context.md +11 -0
  10. package/mcp.pi.json +14 -0
  11. package/package.json +21 -6
  12. package/skills/ai-readiness/SKILL.md +50 -0
  13. package/skills/api-discovery/SKILL.md +135 -0
  14. package/skills/api-discovery/reference/orbit.md +101 -0
  15. package/skills/api-documentation/SKILL.md +34 -0
  16. package/skills/api-documentation/reference/rest-api-best-practices.md +47 -0
  17. package/skills/api-engineer/SKILL.md +29 -0
  18. package/skills/api-mocking/SKILL.md +141 -0
  19. package/skills/api-monitoring/SKILL.md +137 -0
  20. package/skills/api-testing/SKILL.md +103 -0
  21. package/skills/bootstrap/SKILL.md +216 -0
  22. package/skills/bootstrap/reference/cli_installation.md +58 -0
  23. package/skills/ci-integration/SKILL.md +121 -0
  24. package/skills/collection-schema-v3/SKILL.md +210 -0
  25. package/skills/collection-schema-v3/reference/environment.md +63 -0
  26. package/skills/collection-schema-v3/reference/other_protocols.md +86 -0
  27. package/skills/datasets/SKILL.md +323 -0
  28. package/skills/flows/SKILL.md +212 -0
  29. package/skills/flows/reference/flow_cli_flags.md +111 -0
  30. package/skills/performance-testing/SKILL.md +71 -0
  31. package/skills/postman-mcp-server/SKILL.md +71 -0
  32. package/skills/postman-mcp-server/references/docs.md +88 -0
  33. package/skills/postman-mcp-server/references/learn.md +73 -0
  34. package/skills/postman-mcp-server/references/mcp-limitations.md +38 -0
  35. package/skills/postman-mcp-server/references/mock.md +101 -0
  36. package/skills/postman-mcp-server/references/search.md +83 -0
  37. package/skills/postman-mcp-server/references/security.md +129 -0
  38. package/skills/postman-mcp-server/references/setup.md +141 -0
  39. package/skills/postman-mcp-server/references/sync.md +85 -0
  40. package/skills/postman-mcp-server/references/test.md +84 -0
@@ -0,0 +1,86 @@
1
+ # Non-HTTP request schemas (v3)
2
+
3
+ Read this only when a collection actually contains one of these request
4
+ types — for the common case, the HTTP schema in the parent
5
+ [SKILL.md](../SKILL.md) is the one that applies.
6
+
7
+ ## GraphQL request
8
+
9
+ - `$kind: "graphql-request"` — required.
10
+ - `url` — string.
11
+ - `order` — optional.
12
+ - `query` — string (the GraphQL query).
13
+ - `variables` — string (a YAML string containing a JSON object).
14
+ - `headers` — array of `{key, value, description?, disabled?}`.
15
+ - `auth` — `{type, credentials}`.
16
+ - `settings` — `{disabledSystemHeaders?}`.
17
+ - `scripts` — array of `{type: "beforeQuery"|"afterResponse", code, language}`.
18
+
19
+ ## gRPC request
20
+
21
+ - `$kind: "grpc-request"` — required.
22
+ - `url` — string.
23
+ - `order` — optional.
24
+ - `methodPath` — string.
25
+ - `methodDescriptor` — string.
26
+ - `message` — `{content: string (JSON)}`.
27
+ - `metadata` — array of `{key, value, description?}`.
28
+ - `auth` — `{type, credentials}`.
29
+ - `settings` —
30
+ `{secureConnection?, strictSSL?, maxResponseMessageSize?, includeDefaultFields?, connectionTimeout?}`.
31
+ - `scripts` — array of `{type: "beforeInvoke"|"afterResponse", code, language}`.
32
+
33
+ ## WebSocket request
34
+
35
+ - `$kind: "websocket-request"` — required.
36
+ - `url` — string.
37
+ - `order` — optional.
38
+ - `headers` — array of `{key, value, description?, disabled?}`.
39
+ - `queryParams` — array of `{key, value, description?, disabled?}`.
40
+ - `settings` — `{handshakeTimeout?, retryCount?, retryDelay?, maxPayload?, strictSSL?}`.
41
+
42
+ ## Socket.IO request
43
+
44
+ - `$kind: "socket.io-request"` — required.
45
+ - `url` — string.
46
+ - `order` — optional.
47
+ - `headers` — array of `{key, value}`.
48
+ - `queryParams` — array of `{key, value}`.
49
+ - `events` — array of `{name, description?, subscribeOnConnect: boolean}`.
50
+ - `settings` — `{version?, path?, handshakeTimeout?, retryCount?, retryDelay?, strictSSL?}`.
51
+
52
+ ## MQTT request
53
+
54
+ - `$kind: "mqtt-request"` — required.
55
+ - `url` — string.
56
+ - `order` — optional.
57
+ - `clientId` — string.
58
+ - `version` — `4 | 5`.
59
+ - `topics` — array of
60
+ `{name, qos: 0|1|2, subscribe: boolean, description?, settings: {noLocal?, retainAsPublished?, retainHandling?, subscriptionIdentifier?}}`.
61
+ - `lastWill` — `{topic, payload, qos, retain, type: "text"|"json", properties: {messageExpiryInterval?, contentType?}}`.
62
+ - `properties` —
63
+ `{sessionExpiryInterval?, receiveMaximum?, maximumPacketSize?, requestResponseInformation?, userProperties: [{key, value}]}`.
64
+ - `settings` — `{cleanSession?, keepAlive?, autoReconnect?, connectionTimeout?, strictSSL?}`.
65
+
66
+ ## MCP request
67
+
68
+ - `$kind: "mcp-request"` — required.
69
+ - `transport` — `"sse" | "stdio"`.
70
+ - `order` — optional.
71
+ - SSE shape: `{url, headers?, message, auth?, settings: {strictSSL?, requestTimeout?, sessionTimeout?}}`.
72
+ - STDIO shape: `{command, env: [{key, value}], message, auth?, settings: {requestTimeout?}}`.
73
+
74
+ ## LLM request
75
+
76
+ - `$kind: "llm-request"` — required.
77
+ - `url` — string.
78
+ - `order` — optional.
79
+ - `config` — `{model, provider}`.
80
+ - `userPrompts` — array of `{id, value, timestamp, active, type: "text"}`.
81
+ - `systemPrompts` — array of `{id, value, timestamp, active, type: "text"}`.
82
+ - `mcpConfig` — optional string (JSON config).
83
+ - `enabledTools` — optional array of strings.
84
+ - `auth` — `{type, credentials}`.
85
+ - `settings` —
86
+ `{temperature?, maxToken?, streamResponse?, responseFormatJSON?, topP?, presencePenalty?, frequencyPenalty?, maxSteps?, streamTools?}`.
@@ -0,0 +1,323 @@
1
+ ---
2
+ name: datasets
3
+ description: Query CSV and JSON files, spreadsheet exports, and live databases (MySQL, PostgreSQL, SQL Server, or anything with a JDBC driver JAR) as one SQL surface; join across them; save a query as a named view so it can be rerun without re-pasting the SQL; then drive a collection run one iteration per row — feeding it the rows a query returns instead of a hardcoded data file — or read rows from scripts via `pm.datasets()`. Use when the user wants to run or loop a collection over rows of test data, parameterize a run from a CSV or spreadsheet or database table, query or join data across files and tables, save or rerun a query without pasting it again, use a query's result rows as the input for a run in place of hardcoded JSON or a data file, point Postman at a JDBC driver, work out where database credentials get stored, or names a Postman dataset or view. Covers `postman dataset` (`source`, `view`, `query`, `jdbc`) and `--iteration-data-dataset`/`--iteration-data-view`/`--dataset` on `collection run`.
4
+ ---
5
+
6
+ # Datasets
7
+
8
+ ## Required CLI version
9
+
10
+ This skill documents the dataset commands as they behave **after**
11
+ postman-cli#1323 (AUTO-987, the spurious `No authorization data found`
12
+ notice) and postman-cli#1340 (AUTO-999/AUTO-998, one datasource per
13
+ worksheet plus the help-text fixes). Both are needed; 1.62.0 has neither.
14
+ Check with `postman --version` before trusting the worksheet and
15
+ auth-notice rules below, and on an older CLI expect `source add --file
16
+ book.xlsx` to add a workbook as a single unqueryable source (in a cloud
17
+ dataset too), `source update --file book.xlsx` to be accepted and rewrite the
18
+ source to `format: csv`, and every logged-out `--iteration-data-dataset` run
19
+ to print the notice.
20
+
21
+ ## Overview
22
+
23
+ A dataset is a Postman entity that names one or more *datasources* and
24
+ presents them as SQL tables. It lives either in a Postman workspace or in the
25
+ repository, and the same commands work on both — with one carve-out, a
26
+ spreadsheet source, covered below. It is not a data file — it is
27
+ a layer over data files and databases, and the value is in that layer:
28
+ heterogeneous
29
+ sources (a CSV and a Postgres table) become joinable in one query, and a
30
+ saved *view* turns a query into a named, reusable result set that a
31
+ collection run can iterate.
32
+
33
+ Local and cloud are the same commands. Every verb that acts on an *existing*
34
+ dataset — `get`, `query`, `delete`, and every `source` and `view`
35
+ subcommand — takes either a `.dataset.yaml` path or a cloud dataset id and
36
+ routes accordingly. Two verbs name a location instead of an existing
37
+ dataset: `list` takes a path or directory (its cloud form is
38
+ `-w <workspaceId>`), and `create` takes the path to write (its cloud form is
39
+ `-w` with no path, since the id does not exist yet). `jdbc inspect` takes
40
+ neither — it reads a driver JAR and touches no dataset at all.
41
+
42
+ There is no `dataset push` verb — but that does not mean local and cloud are
43
+ sealed off from each other. Datasets are a workspace entity, so
44
+ `postman workspace push` syncs them to the bound workspace along with
45
+ collections, environments and the rest, and `postman workspace pull` brings
46
+ them back down. Reach for those when the whole repo should move; the
47
+ `dataset` verbs below are for working on one dataset in place.
48
+
49
+ ## Core knowledge
50
+
51
+ - **Datasets are the current way to drive a run from data.** They supersede
52
+ passing a flat file with `-d`/`--iteration-data`: a dataset gives the same
53
+ row-per-iteration behaviour, and on top of it SQL to filter and shape rows,
54
+ joins across several sources, a live database instead of an export, named
55
+ views that can be rerun, and `pm.datasets()` access from scripts. Reach for
56
+ a dataset by default when someone wants to run a collection over rows of
57
+ data; `-d` remains available for a one-off file and stays the lighter option
58
+ when nothing more is wanted.
59
+
60
+ - **A spreadsheet becomes one source per worksheet, not one source — and
61
+ only in a local dataset.** The engine reads Excel and OpenDocument
62
+ workbooks (`xlsx`, `xls`, `ods`) as well as CSV and JSON, and
63
+ `source add --file book.xlsx` enumerates the sheets and adds each as its own
64
+ datasource — matching what the Postman app does. There is no flag for
65
+ picking a sheet, by design. Three boundaries come before anything else:
66
+
67
+ - **Local datasets only.** Adding a workbook to a *cloud* dataset is
68
+ refused with `SPREADSHEET_CLOUD_UNSUPPORTED`, with or without `--upload`:
69
+ a cloud add posts one datasource with no worksheet selector and the cloud
70
+ service is never handed the bytes to fan the workbook out itself, so it
71
+ would persist exactly the unqueryable source the local path exists to
72
+ prevent. CSV and JSON work on both. This is the carve-out to
73
+ "local and cloud are the same commands" — put the workbook in a local
74
+ `.dataset.yaml`.
75
+ - **`xlsx`, `xls` and `ods` only.** `.xlsm`, `.xlsb` and `.numbers` are
76
+ unmistakably workbooks that the engine cannot read, so extension
77
+ inference refuses them with `WORKBOOK_FORMAT_UNSUPPORTED` rather than
78
+ letting them fall through to the `csv` default and write a source that
79
+ fails every query. Re-save as `.xlsx`, or pass `--format csv` only if the
80
+ file really is delimited text.
81
+ - **`-n` is optional for a workbook, and ignored.** It is required for
82
+ every other source kind, but worksheet sources are named after their
83
+ sheets, so a `-n` passed here changes nothing and earns a
84
+ `NAME_UNUSED_FOR_SPREADSHEET` warning.
85
+
86
+ Each source is named `source_<sheet>`, with anything outside
87
+ `[a-zA-Z0-9_]` replaced by `_`, and `_2`/`_3` appended on collision —
88
+ collision being judged on the engine's *table* key rather than on the
89
+ literal name, so two sheets that normalise onto one table are given
90
+ distinct names instead of registering one table twice and failing every
91
+ query on the dataset. A workbook with People, Orders and "Sales Q3 2026"
92
+ therefore gives `source_People`, `source_Orders` and
93
+ `source_Sales_Q3_2026`. The `-n` you passed does **not** appear in them —
94
+ the scheme matches the Postman app (and DCS server-side), so a workbook
95
+ added from the CLI and the same one added from the app produce identical
96
+ source names and survive a push/pull round trip.
97
+
98
+ Those are *source* names, and a source name is not always a table name.
99
+ **Take the queryable name from the command's own output instead of deriving
100
+ it.** `source add` prints a line per sheet —
101
+ `"source_People" (id: …) from worksheet "People"` — and appends
102
+ `, queryable as "<table>"` whenever the table differs, so a `売上` sheet is
103
+ reported as `source___`, queryable as `source`, and `FROM source` is the
104
+ query. Under `--json` the same thing arrives as `sources[]`, one
105
+ `{id, name, worksheet, table}` entry per worksheet and present for every
106
+ workbook add however many sheets it found; `table` is the field a `FROM`
107
+ clause takes. Still don't copy `name` into a `FROM` clause verbatim, and
108
+ note that a `source_` prefix is correct here and wrong for a source you
109
+ named yourself, so do not carry the habit across.
110
+
111
+ **`source update` cannot make a worksheet source, and now refuses to try.**
112
+ Both halves are hard refusals with a code, and nothing is written:
113
+ `--file <workbook>` fails `SPREADSHEET_FILE_NOT_UPDATABLE` (`.xlsm`,
114
+ `.xlsb` and `.numbers` included) and `--format xlsx|xls|ods` fails
115
+ `SPREADSHEET_FORMAT_NOT_UPDATABLE`, because the command patches `format`
116
+ and `location` field-wise and has no way to pin a worksheet. What is still
117
+ *allowed* and still destructive is `update --file other.csv` on a source
118
+ that already has a worksheet: that patch carries no `source_options`, so
119
+ the stale `spreadsheet.worksheet` selector stays pinned to a file with no
120
+ worksheets and the source stops being queryable (AUTO-1000). Remove the
121
+ source and re-add the workbook with `source add`.
122
+
123
+ - **`--format` is not validated.** Its help text lists the real formats, but
124
+ the flag accepts any string and writes it straight into the manifest, so a
125
+ typo becomes a source that fails only later at query time. Pass it only to
126
+ override inference deliberately; otherwise let the file extension speak.
127
+ - **A datasource's table name is its `name` *normalised*, not its `name`.**
128
+ Before exposing a source as a table the engine lowercases the name,
129
+ collapses every run of `_` to a single `_`, and strips leading and trailing
130
+ `_`. So `-n users` really is `FROM users`, but `-n Sales__Q3_` is
131
+ `FROM sales_q3` — and `FROM Sales__Q3_`, the name you passed and the name
132
+ the CLI echoes back, fails `SQL_UNKNOWN_TABLE`. Case alone is safe (SQL
133
+ identifiers are case-insensitive, so `FROM MixedCase` still finds
134
+ `mixedcase`); underscore runs and edge underscores are not. Keep source
135
+ names already-normalised and the two can never diverge. A workbook add
136
+ reports each sheet's table itself (`queryable as …`, or `sources[].table`
137
+ under `--json`); for anything else, on the federated path
138
+ `SELECT name FROM sqlite_master WHERE type='table'` lists the real ones.
139
+ **The CLI's own `-h` examples say `FROM source_users`, and they are
140
+ wrong** — there is no `source_` prefixing for a source you named
141
+ yourself, and `source_users` fails `SQL_UNKNOWN_TABLE`. Trust the normalised source
142
+ name, not the example text.
143
+ - **Federated vs native is the central query decision.** With no `--source`,
144
+ the query runs through a federated SQLite layer that can join across every
145
+ *federatable* source in the dataset — which is all of them except JDBC, per
146
+ the next rule. With `--source <name>`, it is sent to that one
147
+ datasource in *its own SQL dialect* — which is the only thing that works
148
+ for JDBC sources, and what you want for dialect-specific SQL
149
+ (`now() - interval '1 day'`). `dataset query -s` and
150
+ `dataset view create -s` take the same reference. They are different
151
+ execution paths, not fallbacks for each other — adding or dropping
152
+ `--source` to make a failing query work changes what the query *means*.
153
+ - **JDBC is the one source type that cannot federate.** A native
154
+ `--type mysql|postgresql|sqlserver` source *does* join against a CSV in one
155
+ federated query, which is the main reason to build a mixed dataset. A
156
+ `--type jdbc` source does not appear in the federated layer at all: query
157
+ it without `--source` and it fails `SQL_UNKNOWN_TABLE`, exactly as a
158
+ misspelled table would. So a JDBC source cannot be joined to anything —
159
+ if you need that join, add the database as its native type instead.
160
+ - **Local does not mean free, and the plan gate keys off source type, not
161
+ dataset location.** CSV/JSON sources run fully offline, logged out. Any
162
+ *database* source — including one inside a purely local YAML — forces
163
+ authentication and an entitlement check: MySQL and PostgreSQL need a paid
164
+ plan, and **JDBC and SQL Server need Enterprise**
165
+ (`… data sources require an Enterprise plan.`, HTTP 402).
166
+ - **A view's result set is iteration data.** `collection run
167
+ --iteration-data-dataset <pathOrId> --iteration-data-view <nameOrId>`
168
+ runs one iteration per row, with each column bound as a variable
169
+ (`{{name}}`). Both flags are required together, and the pair is mutually
170
+ exclusive with `-d/--iteration-data`.
171
+ - **On a dataset run, `No authorization data found` means a source really
172
+ does need auth.** A file-backed dataset needs none, and a logged-out run
173
+ over one is silent. So if that line appears on an
174
+ `--iteration-data-dataset` run, read it as signal: a **database** source is
175
+ in play — `jdbc`, `mysql`, `postgres`/`postgresql` or `sqlserver`, and a
176
+ `postmancloudfile` source is *not* one of those and does not trigger it —
177
+ or you passed a cloud dataset id or a cloud collection, or the manifest
178
+ could not be read, those last three all landing on the same fail-closed
179
+ branch. What it is *not* is a verdict on the run — a plain
180
+ `collection run` with no dataset flags still prints it whenever you are
181
+ logged out, because it comes from the run command rather than anything
182
+ dataset-related.
183
+ - **`--dataset <pathOrDir>` is the other consumption path** — repeatable,
184
+ and it exposes datasets to scripts as `pm.datasets(<id>)` rather than
185
+ driving iterations. Resolution is lazy: a run that never calls
186
+ `pm.datasets` parses nothing and needs no auth. An unparseable YAML is
187
+ skipped with a `[pm.datasets] skipped …` warning, not a failed run — so a
188
+ silently absent dataset looks like a script bug.
189
+ - **Query parameters are positional.** `$1, $2` in the SQL, `-p` values in
190
+ order. Views can be parameterized too, but a parameterized view **cannot**
191
+ drive iteration data — `collection run` has nowhere to pass `-p`, and it
192
+ fails as an opaque execution error. Keep iteration views parameter-free.
193
+ - **Dataset commands never touch `.postman/resources.yaml`.** Unlike mocks,
194
+ there is no repo-level registry entry to commit or clean up — the
195
+ `.dataset.yaml` and its `data_dir` are the whole artifact.
196
+ - **`data_dir` is not only your data.** The local engine writes its own state
197
+ in there next to the copied files — `data.db`, `meta.db`, `daemon.log`,
198
+ `config/`, and a uuid-named directory. Commit the manifest and the source
199
+ files; ignore the rest, or the repo starts carrying a query cache and a log.
200
+ `daemon.log` is also the first place to look when the engine itself, rather
201
+ than a query, is what failed.
202
+
203
+ ## Process
204
+
205
+ 1. **Scaffold.** `postman dataset create ./postman/datasets/NAME/NAME.dataset.yaml
206
+ --name "NAME"` writes a four-line manifest with a generated id and
207
+ `data_dir: .resources`. The cloud form is `create --name "NAME" -w <workspaceId>`
208
+ with no path.
209
+ 2. **Attach sources.** `postman dataset source add -d <dataset> -n <table>
210
+ --file ./users.csv` **copies** the file into `data_dir` — pass
211
+ `--ref-only` to reference it in place instead — but note it records an
212
+ **absolute** path, so a `--ref-only` dataset is machine-local and does not
213
+ survive being committed and cloned elsewhere. Extensions
214
+ pick the format only when `--format` is absent; contents are never
215
+ sniffed, so a `.txt` holding JSON needs `--format json`. For a cloud
216
+ dataset, `--file` alone registers a *local-filesystem* source read by the
217
+ local engine; `--upload` is what actually puts the data in the cloud.
218
+ Either way a cloud dataset takes csv and json only — a workbook is refused
219
+ there.
220
+ 3. **For a *JDBC* source, start from `jdbc inspect`.**
221
+ `postman dataset jdbc inspect ./drivers/pg.jar` maps straight onto the
222
+ `source add` flags: `suggestedUrlTemplate` → `--url-template`,
223
+ `templateVariables` → `--var`, `connectionProperties` → `--prop`,
224
+ `driverClass` → `--driver-class`. A second source on the same database
225
+ reuses all of it with `--from-source <name>`. A connection test runs
226
+ before the write, so a JDBC source that cannot connect is never persisted
227
+ (`--no-test` opts out). A native `--type mysql|postgresql|sqlserver`
228
+ source needs none of this — no driver JAR, no inspect step, just
229
+ `--host/--port/--database/--user/--password` — and it is **not**
230
+ connection-tested before the write, so run `source test` yourself after
231
+ adding one.
232
+ 4. **Explore with ad-hoc SQL before saving anything.**
233
+ `postman dataset query <dataset> -q "SELECT …"`. Get the query right
234
+ here — a view is just a query you have already proven.
235
+ 5. **Save the query as a view.** `postman dataset view create -d <dataset>
236
+ -n "Active" -q "SELECT …"`, then `view run "Active" -d <dataset>` to
237
+ confirm the rows. This is the step that makes the dataset usable by a
238
+ run.
239
+ 6. **Drive the run.** `postman collection run <collection>
240
+ --iteration-data-dataset <dataset> --iteration-data-view "Active"`.
241
+ Confirm the iteration count matches the row count — that is the only
242
+ proof the wiring works.
243
+
244
+ ## Critical rules
245
+
246
+ 1. **Secrets are only avoidable on the JDBC path, and that decides which
247
+ source type to use.** A credential passed as a **literal** lands in three
248
+ places: `ps` output, shell history, **and clear text in the dataset YAML**
249
+ (or the cloud request body). The CLI warns about exactly those three, and
250
+ only for literals. What differs by source type is whether there is an
251
+ alternative:
252
+ - **JDBC (`--var`, `--prop`): yes, and it avoids all three.**
253
+ `--var name=vault:<vaultId>/<secretId>` stores a `{$vaultId,$secretId}`
254
+ pointer and resolves it at query time, so the secret itself reaches none
255
+ of the three — only the reference travels through argv. `--vars-file`
256
+ reads the same values from a JSON file and `--vars-file -` from stdin,
257
+ which is the one way to keep a value out of `ps` and shell history; it
258
+ accepts vault refs too, and a *literal* passed that way still lands in
259
+ the YAML in clear text. Local Vault secrets are not supported — Shared
260
+ Vault only. A literal secret in `--url-template` is rejected outright: a
261
+ literal has no `{{name}}` to route through `--var`, so nothing could
262
+ mask it.
263
+ - **Native `--type mysql|postgresql|sqlserver` (`--user`, `--password`):
264
+ no.** The CLI says so on every write —
265
+ `Secret references for database credentials are not yet supported by
266
+ Postman CLI.` There is no vault form of these flags. The credentials
267
+ land in the YAML in clear text or the source does not exist.
268
+
269
+ So when credentials must not sit in a committed file, reach for
270
+ `--type jdbc` with Vault refs rather than the native type for the same
271
+ database. Otherwise treat that YAML as a secret-bearing file and keep it
272
+ out of version control.
273
+ 2. **"The dataset operation failed with a server error. Please retry." is
274
+ usually not a server error and retrying will not help.** It is the
275
+ generic wrapper over engine errors, including your SQL being wrong.
276
+ Re-run with `--debug` to get the real code — `engineCode=SQL_UNKNOWN_TABLE`
277
+ for a bad table name, and so on. Read that before changing anything.
278
+ 3. **When a query fails, isolate the layer with
279
+ `postman dataset source test -d <dataset> -n <source>`.** It opens and
280
+ closes a real connection using the stored config, resolving Vault
281
+ references the way a query would, which separates "the source is broken"
282
+ from "the SQL is wrong". File and URL sources have no connection and
283
+ report `SOURCE_NOT_TESTABLE` — that is the expected answer, not a fault.
284
+ 4. **`--dataset` on a cloud collection does not scope access.** A script can
285
+ call `pm.datasets(<anyId>)` for any dataset the logged-in session can
286
+ read. Only run collections you trust against a logged-in cloud session.
287
+ 5. **`dataset delete` is permanent and deliberately asymmetric** — it
288
+ removes the manifest but preserves the source files, because references
289
+ can cross directory boundaries. An empty `data_dir` is removed unless
290
+ `--keep-resources` is passed. Confirm before running it on a cloud id,
291
+ where there is no file left behind to recover from.
292
+ 6. **Pass `--json` when parsing.** Both success and failure go to stdout, so
293
+ `--json 2>/dev/null | jq .` works either way, and failures carry a stable
294
+ `error.code` (`CONNECTION_FAILED`, `DRIVER_CLASS_AMBIGUOUS`,
295
+ `CONFIG_VALUE_MISSING`, …) plus `remediation`. Branch on the code, never
296
+ on the prose.
297
+
298
+ ## Anti-patterns
299
+
300
+ - **Don't add a database source to make a demo "more realistic."** It
301
+ converts a zero-setup offline dataset into one that needs login, a paid
302
+ plan, network reachability, and (for JDBC/SQL Server) Enterprise. Use CSV
303
+ unless the live data is the point.
304
+ - **Don't run `postman dataset list` with no arguments** expecting the local
305
+ datasets. Bare `list` is the *cloud* form and errors without `-w` outside
306
+ a Postman-managed project; pass a path or directory for local ones.
307
+ - **Don't hand-edit `.dataset.yaml` to add a source.** `source add` runs the
308
+ connection test (JDBC), id generation, and secret validation that a
309
+ hand-edited entry skips — and the resolver re-inspects every YAML
310
+ precisely so a hand-edited file cannot bypass the source gate.
311
+
312
+ ## Verification
313
+
314
+ A dataset is not working because `create` and `source add` exited 0 — those
315
+ prove only that the write went through: a manifest locally, a workspace
316
+ entity in the cloud, and on the JDBC path a connection that opened, unless
317
+ `--no-test` skipped that test. None of it proves a query returns rows. Run an actual query and state
318
+ the row count and columns you got back. For a run, state the iteration count
319
+ and confirm it equals the view's row count; three rows producing one
320
+ iteration means the view, not the collection, is what to look at. Say which
321
+ execution path ran (federated or `--source` native) and whether the dataset
322
+ was local or cloud — that determines whether the numbers reflect live data
323
+ or a copied snapshot in `data_dir`.
@@ -0,0 +1,212 @@
1
+ ---
2
+ name: flows
3
+ description: Runs, deploys, and debugs Postman Flows from the command line — executing a flow file locally, triggering a deployed flow over its webhook, deploying one so it becomes callable, and tracing a failed run to the block that broke. Use when the user names a flow and an action ("run the Checkout flow", "deploy this flow", "why did that flow run fail", "what flows do I have"). Covers `postman flows list`, `run`, `trigger`, `deploy`, `update`, `list-runs`, and `get-run`.
4
+ ---
5
+
6
+ # Postman Flows
7
+
8
+ ## Overview
9
+
10
+ Listing flows, running them, deploying them so they become callable, and
11
+ tracing a failed run to the block that caused it — all through
12
+ `postman flows`.
13
+
14
+ ## Core knowledge
15
+
16
+ A flow is a graph of blocks, not a script. That single fact drives the rest of
17
+ this skill: a flow has two independent execution paths, and its HTTP response
18
+ describes one block rather than the whole graph, so debugging takes a
19
+ different command than running.
20
+
21
+ ### Local file vs deployed artifact
22
+
23
+ `run` and `trigger` are not two ways to execute one flow. Postman Flows has
24
+ two Native Git modes, and they are isolated from each other:
25
+
26
+ - **Cloud View** (the default) syncs flows to Postman Cloud, which is what
27
+ makes them shareable and **deployable** — so Cloud View is the only side
28
+ `deploy`, `trigger`, `update`, `list-runs` and `get-run` ever address.
29
+ - **Local View** stores flows as JSON in a local Git repo, updated as they are
30
+ edited. Those flows **cannot be shared or deployed**, have no snapshots, and
31
+ are isolated from the flows in Cloud View.
32
+
33
+ | | `flows run <path>` | `flows trigger <flowId>` |
34
+ | --- | --- | --- |
35
+ | Executes | a flow JSON file on this machine | the cloud-deployed flow, via its webhook |
36
+ | Returns | status, output, test results, exit code | Run ID + HTTP status + response body |
37
+ | Observability | own stdout, `--output`, `--reporters` | `get-run`, per block |
38
+ | Environment file | `-e/--environment` | not supported |
39
+
40
+ `run` exits nonzero on failure, which is what lets a CI job gate on it.
41
+ `trigger` goes through the real webhook URL, so it exercises the deployed path
42
+ end-to-end — auth and trigger configuration included — and registers a cloud
43
+ run that `get-run` can explain block by block.
44
+
45
+ `postman init` scaffolds `postman/flows/`, and Postman's `flows run` examples
46
+ use that path. Note what puts files there: the Git-connected Flows experience
47
+ is **desktop-app only**, so `postman/flows/*.json` is written by the desktop
48
+ app's Local View, not by the CLI — `workspace push`/`pull` carry no flows
49
+ handling whatever else they sync. Don't tell a user to `workspace pull` to
50
+ obtain a flow file.
51
+
52
+ ### What deploying buys, and what it requires
53
+
54
+ Deploying puts the flow in Postman's cloud and attaches an HTTP trigger, which
55
+ is what makes it reachable by schedules, webhooks, third-party apps, and other
56
+ APIs — the flow stops being something a human opens and becomes callable
57
+ infrastructure.
58
+
59
+ Three preconditions sit outside the CLI, so no flag or retry satisfies them:
60
+ the flow must be in Cloud View, its Start block must be configured with an API
61
+ request trigger, and its canvas must have a Response block. Check these before
62
+ re-running a failed deploy with different arguments.
63
+
64
+ `--path` is a suffix appended to a generated base URL, not a full URL.
65
+
66
+ ### Inputs: `-i` versus a scenario
67
+
68
+ A scenario is a named input set stored **in the flow definition**, generated
69
+ when someone adds an input to the Start block. Because it travels with the
70
+ flow, `-s "Staging"` is reproducible across invocations and across people,
71
+ where `-i key=value` is per-invocation. Start-block inputs can be declared
72
+ secret, which is what `--show-secrets` unmasks in dry-run output.
73
+
74
+ Precedence: `-s` supplies payload, headers, and query; `--headers` and
75
+ `--query` override it; `-i`/`-f` override its values.
76
+
77
+ ### Identifiers
78
+
79
+ `flows list` is the only way to turn a flow name into an id —
80
+ `.postman/resources.yaml` maps collections to cloud ids but has no flows
81
+ section, so there is nothing local to read. Both `list` and `list-runs`
82
+ **require** `-w/--workspace`; take that id from `workspace.id` in
83
+ `.postman/resources.yaml`, which `bootstrap` records.
84
+
85
+ Run IDs have no single documented shape (`session-abc123` and `main/1a123ab1`
86
+ both appear in Postman's own material). Use whatever `trigger` or `list-runs`
87
+ printed, verbatim, and apply the same rule to flow ids.
88
+
89
+ ### Plan and permission gating
90
+
91
+ `flows run` is documented as Enterprise-only, and the cloud subcommands need
92
+ `postman login`. `Access denied. Please check your permissions for the
93
+ specified resource.` on *every* workspace is a credential-scope or plan
94
+ signal, not a wrong-workspace signal — and never means the workspace has no
95
+ flows.
96
+
97
+ ## Deploying: propose, confirm, then verify
98
+
99
+ Deploy is the one multi-phase workflow here, because it is mutating and
100
+ because its result is only half-useful without the follow-up check.
101
+
102
+ 1. **Resolve the id.** `flows list --workspace <id> --filter "Checkout"`. On
103
+ multiple matches, show name + id + last-updated and let the user pick.
104
+ 2. **Propose the path.** Derive it from the flow name — "Checkout" →
105
+ `/checkout` — so the user is confirming a concrete value rather than
106
+ answering an open question. Raise `--auth` here if the trigger will be
107
+ reachable by anyone who learns the URL.
108
+ 3. **Confirm, then run** `flows deploy <flowId> --path /checkout`.
109
+ 4. **Report the Trigger URL and whether the trigger is enabled.** A deploy can
110
+ land with the trigger off, which looks identical to a broken deploy at call
111
+ time. If it is off, offer `flows update <flowId> --trigger on`.
112
+
113
+ When the deploy existed only so the flow could be run, trigger it in the same
114
+ turn and report the Run ID — deploy-then-trigger is one job.
115
+
116
+ ## Running and triggering
117
+
118
+ Show the command before running it, and map the request onto flags: inputs to
119
+ `-i`, a payload file to `-f`, query to `-q`, headers to `--headers`, a named
120
+ scenario to `-s`.
121
+
122
+ ```bash
123
+ postman flows run postman/flows/checkout.json -i amount=4200
124
+ postman flows trigger <flowId> -i amount=4200
125
+ ```
126
+
127
+ `run` is documented as Enterprise-only, so check the plan before building a
128
+ workflow on the local path. Where the flow is already in Cloud View, `trigger`
129
+ covers the gap; a Local View flow has no such fallback, since it cannot be
130
+ deployed.
131
+
132
+ `-n/--dry-run` on `trigger` prints the resolved URL and payload without
133
+ sending — worth reaching for when a flow writes to real systems, since a
134
+ trigger is not a read-only probe. For CI, `--output json` and `--reporters
135
+ html` persist results, and `--workspace` is required if the flow contains
136
+ connector blocks (it fails at the block, not at startup).
137
+
138
+ Report the Run ID on every trigger, including successes; it is the only handle
139
+ on the run afterwards.
140
+
141
+ Two failures are recoverable rather than terminal, and both recover through a
142
+ confirmed mutation. A 404 hinting `To deploy it, run: postman flows deploy`
143
+ means the flow exists but was never deployed — offer the deploy above, then
144
+ re-trigger. A disabled-trigger error means it is deployed but not accepting
145
+ calls — offer `flows update <flowId> --trigger on`, then trigger.
146
+
147
+ ## Debugging a run
148
+
149
+ A trigger's response body is the Response block's output. A flow can answer
150
+ 200 with a failed block upstream, and a 500 says nothing about which block
151
+ produced it — so read the run, not the response.
152
+
153
+ ```bash
154
+ postman flows list-runs --workspace <id> --flow <flowId> --range 3d
155
+ postman flows get-run --run-id <runId> --logs
156
+ ```
157
+
158
+ `list-runs` recovers a Run ID nobody wrote down; its `--range` defaults to
159
+ `1h`, so widen it before concluding a run is missing. Start `get-run` without
160
+ `--logs` and add them when the summary does not explain the failure;
161
+ `--filter` narrows to a block-id prefix.
162
+
163
+ Report the failing block, the reason, and the run status:
164
+
165
+ ```
166
+ Run session-abc123 — failed
167
+ Failing block: "HTTP Request (Get Orders)"
168
+ Reason: downstream returned 504 after 10s timeout
169
+ Status: error
170
+ ```
171
+
172
+ ## Critical Rules
173
+
174
+ 1. **Resolve ids, never infer them.** A name is not an id, and no id format is
175
+ documented well enough to validate against. Ambiguous name → present
176
+ candidates and ask.
177
+ 2. **`deploy` and `update` need explicit confirmation.** They change what the
178
+ flow does for every caller: a deploy exposes a trigger path, `--trigger
179
+ on|off` starts or stops accepting calls, and `--auth off` removes
180
+ authentication from a live trigger.
181
+ 3. **Report the failing block, not the log.** `--logs` output is input to your
182
+ analysis; the user needs the block, the reason, and the status.
183
+ 4. **Surface CLI errors verbatim** and read them literally. "Flow file not
184
+ found", a required-option error, and "Access denied" have three different
185
+ fixes, and only the last is about permissions.
186
+ 5. **A missing or unauthenticated CLI is `bootstrap`'s job** — route there
187
+ rather than improvising an install or a second login.
188
+
189
+ ## Anti-patterns
190
+
191
+ 1. **Don't substitute `run` for `trigger` when a flow isn't deployed.** A
192
+ green local run says nothing about the deployed path a caller hits, and a
193
+ Local View flow cannot be deployed at all.
194
+ 2. **Don't hunt for a different workspace id when access is denied across
195
+ every workspace you try.** A blanket denial points at the credential's
196
+ scope or the plan, not at the id.
197
+ 3. **Don't pass `-x/--suppress-exit-code` in CI.** It makes a failed flow
198
+ report success to the pipeline, which removes the only thing gating it.
199
+ 4. **Don't put reusable inputs on the command line.** A payload that matters
200
+ more than once belongs in a Start-block scenario, where it travels with the
201
+ flow.
202
+
203
+ ## Reference
204
+
205
+ - [Flows CLI flags](reference/flow_cli_flags.md) — full flag tables per
206
+ subcommand, the BETA dataset-iteration flags, and the short-flag collisions
207
+ between subcommands. Read before composing a command with flags not shown
208
+ above.
209
+ - `bootstrap` skill — CLI install, login, and the workspace id these commands
210
+ require.
211
+ - `api-discovery` skill — `postman search flows` finds a flow by text across
212
+ Postman, a different dataset from `flows list`'s workspace enumeration.