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

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
package/README.md CHANGED
@@ -21,10 +21,10 @@ dependencies, ownership, runtime behavior, and the likely impact of a change.
21
21
  Install Postman in every compatible coding agent detected on your machine:
22
22
 
23
23
  ```bash
24
- npx @postman/postman-plugin@next
24
+ npx @postman/postman-plugin
25
25
  ```
26
26
 
27
- One command configures **Claude Code, Codex, Cursor, Kimi Code and OpenCode**.
27
+ One command configures **Claude Code, Codex, Cursor, Kimi Code, OpenCode and Pi**.
28
28
  Run it again to update, `status` to see what's installed, and `remove` to
29
29
  uninstall; `--agent <id>` limits any of them to one agent.
30
30
 
@@ -54,6 +54,18 @@ claude plugin install postman@postman
54
54
  codex plugin add postman@postman
55
55
  ```
56
56
 
57
+ ### Pi
58
+
59
+ [View Postman in Pi's package gallery](https://pi.dev/packages/@postman/postman-plugin)
60
+
61
+ ```bash
62
+ pi install npm:@postman/postman-plugin
63
+ ```
64
+
65
+ `pi update npm:@postman/postman-plugin` updates it. Sign in to Postman's MCP
66
+ server with `/mcp login postman` inside a Pi session. The shell's `pi mcp login`
67
+ doesn't load extensions, so it reports no server named `postman`.
68
+
57
69
  ## Highlights
58
70
 
59
71
  ### Filesystem-first API development
package/dist/cli.js CHANGED
@@ -20,7 +20,13 @@ Options:
20
20
  -y, --yes Don't ask for confirmation (required when not in a terminal)
21
21
  --dry-run Print what would change without changing anything
22
22
  -h, --help Show this help
23
- -v, --version Show the version`;
23
+ -v, --version Show the version
24
+
25
+ Exit codes:
26
+ 0 Done, or nothing needed doing
27
+ 1 Something failed or was blocked, you cancelled, or install found no agent
28
+ 2 Bad usage, or confirmation needed but no terminal (use --yes)
29
+ 3 Done, except a step only you can do (printed as "next:")`;
24
30
  function version() {
25
31
  const manifest = new URL('../package.json', import.meta.url);
26
32
  return JSON.parse(fs.readFileSync(manifest, 'utf8')).version;
@@ -3,4 +3,5 @@ import { codex } from './codex.js';
3
3
  import { cursor } from './cursor.js';
4
4
  import { kimi } from './kimi.js';
5
5
  import { opencode } from './opencode.js';
6
- export const HOSTS = [claudeCode, codex, cursor, kimi, opencode];
6
+ import { pi } from './pi.js';
7
+ export const HOSTS = [claudeCode, codex, cursor, kimi, opencode, pi];
@@ -46,10 +46,13 @@ export const kimi = {
46
46
  if (!(await system.which('npx'))) {
47
47
  blocked('npx is not on PATH');
48
48
  }
49
- await mustRun(system, 'npx', ['-y', PLUGINS_CLI, 'add', REPO, '--target', 'kimi', '--yes'], {
49
+ // Only picks the verb: an unreadable store must not stop the install that could repair it.
50
+ const installed = await kimi.status(system).then((status) => status.installed, () => null);
51
+ // An explicit --package outranks the npm_config_package an outer `npx -p` exports to us.
52
+ await mustRun(system, 'npx', ['-y', `--package=${PLUGINS_CLI}`, 'plugins', 'add', REPO, '--target', 'kimi', '--yes'], {
50
53
  env: { DISABLE_TELEMETRY: '1', DO_NOT_TRACK: '1' }
51
54
  });
52
- return result('done', `installed ${PLUGIN_ID} into ${kimiHome(system)}`, NEXT);
55
+ return result('done', `${installed ? 'updated' : 'installed'} ${PLUGIN_ID} in ${kimiHome(system)}`, NEXT);
53
56
  });
54
57
  },
55
58
  async remove(system) {
@@ -0,0 +1,84 @@
1
+ import path from 'node:path';
2
+ import { PI_SOURCE, REPO, isSameRepo, redact } from '../source.js';
3
+ import { failed, guard, mustRun, parseJson } from './shared.js';
4
+ import { result } from './types.js';
5
+ const NEXT = 'Restart Pi, or run `/reload` in an open session, for the change to take effect.', GIT_PREFIX = /^git:/,
6
+ // Pi's ref is everything after the first `@` in the repo path, slashes included. The path starts
7
+ // after the scp-style `host:` or after the host, so an `@` in URL user-info is never a ref.
8
+ SCP_WITH_REF = /^(git@[^:]+:[^@]*)@/, URL_WITH_REF = /^((?:[a-z][a-z0-9+.-]*:\/\/)?[^/]*\/[^@]*)@/i;
9
+ function agentDir(system) {
10
+ const dir = system.env.PI_CODING_AGENT_DIR;
11
+ if (!dir) {
12
+ return path.join(system.home, '.pi', 'agent');
13
+ }
14
+ return dir === '~' || dir.startsWith('~/') ? path.join(system.home, dir.slice(1)) : dir;
15
+ }
16
+ function withoutRef(source) {
17
+ const url = source.replace(GIT_PREFIX, '');
18
+ return (url.match(SCP_WITH_REF) ?? url.match(URL_WITH_REF))?.[1] ?? url;
19
+ }
20
+ // Pi keys an npm package by its name, so a pinned `npm:@postman/postman-plugin@x` is this
21
+ // package too. A git install of this repo is another package loading the same skills.
22
+ const settingsFile = (system) => path.join(agentDir(system), 'settings.json'), isOurPackage = (source) => source === PI_SOURCE || source.startsWith(`${PI_SOURCE}@`), isRepoClone = (source) => !source.startsWith('npm:') && isSameRepo(withoutRef(source), REPO);
23
+ /** Every package source in Pi's user settings, or `null` when the file can't be parsed. */
24
+ async function packageSources(system) {
25
+ const text = await system.readFile(settingsFile(system));
26
+ if (text === null) {
27
+ return [];
28
+ }
29
+ // Pi parses the file the same way, so a file that fails here fails in `pi` too.
30
+ const settings = parseJson(text.replace(/^\uFEFF/, ''));
31
+ if (!settings || (settings.packages !== undefined && !Array.isArray(settings.packages))) {
32
+ return null;
33
+ }
34
+ return (settings.packages ?? [])
35
+ .map((entry) => (typeof entry === 'string' ? entry : entry?.source))
36
+ .filter((source) => typeof source === 'string');
37
+ }
38
+ async function readableSources(system) {
39
+ return (await packageSources(system)) ?? failed(`${settingsFile(system)} is not valid JSON; fix it and re-run`);
40
+ }
41
+ export const pi = {
42
+ id: 'pi',
43
+ name: 'Pi',
44
+ route: 'installer/package.json',
45
+ async detect(system) {
46
+ return (await system.which('pi')) !== null;
47
+ },
48
+ async status(system) {
49
+ const sources = await packageSources(system);
50
+ if (sources === null) {
51
+ return { installed: null, detail: `could not read ${settingsFile(system)}`, notes: [] };
52
+ }
53
+ const ours = sources.find(isOurPackage), notes = [
54
+ ...(ours && ours !== PI_SOURCE ? [`${ours} is pinned, so an update leaves it at that version`] : []),
55
+ ...sources.filter(isRepoClone).map((source) => `${redact(source)} loads the same skills and will be removed`)
56
+ ];
57
+ return ours ?
58
+ { installed: true, detail: `${ours} in ${settingsFile(system)}`, notes } :
59
+ { installed: false, detail: 'not installed', notes };
60
+ },
61
+ install(system) {
62
+ return guard(async () => {
63
+ const sources = await readableSources(system), installed = sources.some(isOurPackage);
64
+ // Replacement first: if it fails, a git copy of this repo is still a working one.
65
+ await mustRun(system, 'pi', [installed ? 'update' : 'install', PI_SOURCE]);
66
+ for (const source of sources.filter(isRepoClone)) {
67
+ await mustRun(system, 'pi', ['remove', source]);
68
+ }
69
+ return result('done', `${installed ? 'updated' : 'installed'} ${PI_SOURCE} in ${settingsFile(system)}`, NEXT);
70
+ });
71
+ },
72
+ remove(system) {
73
+ return guard(async () => {
74
+ const sources = await readableSources(system), targets = [...(sources.some(isOurPackage) ? [PI_SOURCE] : []), ...sources.filter(isRepoClone)];
75
+ if (!targets.length) {
76
+ return result('skipped', 'not installed');
77
+ }
78
+ for (const source of targets) {
79
+ await mustRun(system, 'pi', ['remove', source]);
80
+ }
81
+ return result('done', `removed ${targets.map(redact).join(', ')}`, NEXT);
82
+ });
83
+ }
84
+ };
@@ -0,0 +1,27 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ /** In the tarball, where `prepack` staged the repo's shared files beside `dist/`. */
5
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'), ENTRY_SKILL = 'api-engineer', SECTION = 'postman';
6
+ /** Pi's skill names are un-namespaced; the shared mandate names them `postman:<skill>` for the other routes. */
7
+ export function toPiSessionContext(source) {
8
+ return source.replace(/`postman:([a-z0-9-]+)`/g, '`$1`');
9
+ }
10
+ /** Reads the mandate and the MCP config from `root`, which is laid out like the repository root. */
11
+ export function postmanExtension(root) {
12
+ return (pi) => {
13
+ const mandate = toPiSessionContext(fs.readFileSync(path.join(root, 'hooks', 'session-start-context.md'), 'utf8')), { mcpServers } = JSON.parse(fs.readFileSync(path.join(root, 'mcp.pi.json'), 'utf8'));
14
+ // A `postman` server in the user's own mcp.json takes precedence over this registration.
15
+ for (const [name, server] of Object.entries(mcpServers)) {
16
+ pi.registerMcpServer(name, server);
17
+ }
18
+ // Pi's stand-in for the SessionStart hook. The mandate routes to a skill, so it goes only
19
+ // where that skill loaded; `pi config` can disable it.
20
+ pi.on('before_agent_start', ({ systemPromptOptions }) => {
21
+ if (systemPromptOptions.skills.some((skill) => skill.name === ENTRY_SKILL)) {
22
+ systemPromptOptions.sections[SECTION] = mandate;
23
+ }
24
+ });
25
+ };
26
+ }
27
+ export default postmanExtension(packageRoot);
package/dist/run.js CHANGED
@@ -1,6 +1,5 @@
1
- export const EXIT = { ok: 0, failed: 1, usage: 2 };
2
- // `manual` counts: the command did not finish, and a script needs to know the user has a step left.
3
- const INCOMPLETE = ['failed', 'blocked', 'manual'];
1
+ export const EXIT = { ok: 0, failed: 1, usage: 2, manual: 3 };
2
+ const FAILED = ['failed', 'blocked'];
4
3
  function padEnd(text, width) {
5
4
  return text + ' '.repeat(Math.max(1, width - text.length));
6
5
  }
@@ -76,11 +75,15 @@ export async function run(system, hosts, options) {
76
75
  }
77
76
  }
78
77
  if (!targets.length) {
79
- system.log(`No supported coding agent found. Supported: ${joinNames(requested)}.`);
78
+ system.log(options.agents.length ?
79
+ 'None of the requested agents was found.' :
80
+ `No supported coding agent found. Supported: ${joinNames(requested)}.`);
80
81
  reports.forEach((report) => system.log(` ${report.result.message}`));
81
- return reports.length && options.command !== 'status' ? EXIT.failed : EXIT.ok;
82
+ // Nothing to remove is a clean remove; nothing to install into is not a successful install.
83
+ return options.command === 'install' || (options.command === 'remove' && reports.length) ? EXIT.failed : EXIT.ok;
82
84
  }
83
- system.log('Found:');
85
+ // "Found:" over "not installed" read to agents as "not found"; the header says both things.
86
+ system.log(`Found ${targets.length} coding agent${targets.length === 1 ? '' : 's'}. Postman in each:`);
84
87
  printStatuses(system, targets, width);
85
88
  reports.forEach((report) => system.log(` ${padEnd(report.host.name, width)}${report.result.message}`));
86
89
  if (options.command === 'status') {
@@ -90,12 +93,12 @@ export async function run(system, hosts, options) {
90
93
  // remove also clears duplicates and half-finished installs that status doesn't count.
91
94
  const command = options.command;
92
95
  if (!options.yes && !system.dryRun) {
96
+ const verb = command === 'install' ? 'install or update Postman in' : 'remove Postman from', names = joinNames(targets.map((target) => target.host));
93
97
  if (!options.isTTY) {
94
- system.log('\nNot running in a terminal, so there is no one to confirm. Re-run with --yes.');
98
+ system.log(`\nNothing changed: there is no terminal to confirm in. To ${verb} ${names}, re-run with --yes (add --agent <id> for only some).`);
95
99
  return EXIT.usage;
96
100
  }
97
- const verb = command === 'install' ? 'Install or update Postman in' : 'Remove Postman from';
98
- if (!(await options.confirm(`\n${verb} ${joinNames(targets.map((target) => target.host))}? [Y/n] `))) {
101
+ if (!(await options.confirm(`\n${verb[0].toUpperCase()}${verb.slice(1)} ${names}? [Y/n] `))) {
99
102
  system.log('Cancelled.');
100
103
  return EXIT.failed;
101
104
  }
@@ -110,5 +113,8 @@ export async function run(system, hosts, options) {
110
113
  for (const { host, result } of reports) {
111
114
  system.log(` ${padEnd(host.name, width)}${padEnd(result.outcome, 9)}${result.message.split('\n')[0]}`);
112
115
  }
113
- return reports.some(({ result }) => INCOMPLETE.includes(result.outcome)) ? EXIT.failed : EXIT.ok;
116
+ if (reports.some(({ result }) => FAILED.includes(result.outcome))) {
117
+ return EXIT.failed;
118
+ }
119
+ return reports.some(({ result }) => result.outcome === 'manual') ? EXIT.manual : EXIT.ok;
114
120
  }
package/dist/source.js CHANGED
@@ -1,8 +1,10 @@
1
- /** Where every host's copy of the plugin comes from. The npm package carries no skills. */
1
+ /** Where every host's copy of the plugin comes from. Pi alone installs the npm package instead. */
2
2
  export const REPO = 'postmanlabs/postman-plugin';
3
3
  export const GIT_URL = `https://github.com/${REPO}.git`;
4
4
  /** The branch every clone this installer makes tracks. */
5
5
  export const BRANCH = 'main';
6
+ /** Unpinned, so `pi update` moves it with each `latest` release; test/pi-package.test.js checks the name. */
7
+ export const PI_SOURCE = 'npm:@postman/postman-plugin';
6
8
  /** Must stay byte-identical to the shim in opencode/README.md; test/routes.test.js enforces it. */
7
9
  export const OPENCODE_SHIM = "export { default } from '../postman-plugin/opencode/src/index.ts';\n";
8
10
  /** Pinned: this third-party CLI writes Kimi's plugin store for us, and an unpinned npx would run whatever is latest. */
@@ -0,0 +1,11 @@
1
+ <EXTREMELY_IMPORTANT>
2
+ You have the Postman plugin.
3
+
4
+ Before responding to any non-trivial API engineering task — designing, implementing, mocking, testing, monitoring, documenting, or deploying an API or Postman Flow — load the `postman:api-engineer` skill and follow it. It is the default entry point and routes to the specific postman skills from there. Pure questions and trivial one-line edits don't need it.
5
+
6
+ When the intent is already specific, you may enter directly into the relevant skill instead: `postman:bootstrap` (link this repo to a Postman workspace), `postman:api-mocking`, `postman:api-testing`, `postman:api-monitoring`, `postman:flows`, `postman:ci-integration`, `postman:api-discovery`, `postman:ai-readiness`, `postman:performance-testing`, `postman:api-documentation`.
7
+
8
+ If you were dispatched as a subagent to execute a specific task, ignore this block — `postman:api-engineer` governs the orchestrating session, and it already shaped your dispatch.
9
+
10
+ User instructions (project instruction files such as AGENTS.md or CLAUDE.md, and direct requests) take precedence over this mandate.
11
+ </EXTREMELY_IMPORTANT>
package/mcp.pi.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "mcpServers": {
3
+ "postman": {
4
+ "type": "http",
5
+ "url": "https://mcp.postman.com/mcp",
6
+ "description": "Postman workspaces, collections, specs, environments, mocks and monitors",
7
+ "headers": {
8
+ "X-Source": "postman-pi-plugin",
9
+ "X-Plugin-Version": "0.1.2-rc.0",
10
+ "User-Agent": "postman-pi-plugin/0.1.2-rc.0"
11
+ }
12
+ }
13
+ }
14
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@postman/postman-plugin",
3
- "version": "0.1.1-rc.0",
4
- "description": "Installs the Postman plugin into every supported coding agent on this machine.",
3
+ "version": "0.1.2-rc.0",
4
+ "description": "Postman's API engineering skills for coding agents: a Pi package, and an npx installer that sets up Claude Code, Codex, Cursor, Kimi Code, OpenCode and Pi.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
7
7
  "author": {
@@ -17,6 +17,8 @@
17
17
  },
18
18
  "bugs": "https://github.com/postmanlabs/postman-plugin/issues",
19
19
  "keywords": [
20
+ "pi-package",
21
+ "pi",
20
22
  "postman",
21
23
  "claude-code",
22
24
  "codex",
@@ -29,13 +31,26 @@
29
31
  "postman-plugin": "dist/cli.js"
30
32
  },
31
33
  "files": [
32
- "dist/"
34
+ "dist/",
35
+ "skills/",
36
+ "hooks/session-start-context.md",
37
+ "mcp.pi.json"
33
38
  ],
39
+ "pi": {
40
+ "extensions": [
41
+ "./dist/pi-extension.js"
42
+ ],
43
+ "skills": [
44
+ "./skills"
45
+ ],
46
+ "image": "https://assets.getpostman.com/common-share/postman-logo-horizontal-320x132.png"
47
+ },
34
48
  "scripts": {
35
49
  "build": "tsc -p tsconfig.json",
36
- "prepack": "npm run build && node scripts/pack-docs.js stage",
37
- "postpack": "node scripts/pack-docs.js clean",
38
- "test": "npm run build && node --test test/*.test.js"
50
+ "prepack": "npm run build && node scripts/pack-repo-files.js stage",
51
+ "postpack": "node scripts/pack-repo-files.js clean",
52
+ "test": "npm run build && node --test test/*.test.js",
53
+ "test:pi-harness": "node scripts/pi-harness.js"
39
54
  },
40
55
  "devDependencies": {
41
56
  "@types/node": "24.5.2",
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: ai-readiness
3
+ description: Scores a Postman collection or an OpenAPI spec for how well an AI agent can discover, understand, call, and recover from errors with it — missing examples, undocumented errors, and ambiguous parameters all cost points. Use when the user asks "is my API agent-ready," "can AI agents use my API," "how agent-friendly is my API," or wants to scan, score, or improve a collection or spec for AI/agent consumption. Covers `postman collection ai-readiness` and `postman spec ai-readiness`.
4
+ ---
5
+
6
+ # AI Readiness
7
+
8
+ ## Overview
9
+
10
+ An "agent-ready" API is one that an AI agent can discover, understand, call correctly, and recover from errors without human intervention. Most APIs aren't there yet.
11
+
12
+ Two ways to run this check, same rubric family, different target — pick by what exists:
13
+
14
+ - `collection ai-readiness <collectionId/path>` scores a Postman collection
15
+ — by cloud ID, local file path, or a `postman/collections/<name>`
16
+ local-mode directory.
17
+ - `spec ai-readiness <spec>` scores an OpenAPI specification directly — by
18
+ cloud ID or local file path — with no collection involved at all.
19
+
20
+
21
+
22
+ ## Scoring
23
+
24
+ The command computes and prints the score itself — read the fields it
25
+ gives you, don't recompute them:
26
+
27
+ - **`readiness`** (score 0-100 + bucket) is the headline number. Buckets,
28
+ low to high: **Limited → Fair → Good → Excellent**.
29
+ - **`confidence`** (`high`/`medium`/`low`) says how many signals it
30
+ could actually measure vs. had to mark `unknown` — a data-quality
31
+ caveat, not part of the score.
32
+
33
+ ## Interpreting Results
34
+
35
+ Report the bucket, score, and confidence the command actually printed
36
+ — don't infer a percentage band. Doc coverage is a modifier via its
37
+ adjustment, not a separate gate; call it out by name when it's `low`,
38
+ since recommendations flag that first. Also state which verb ran
39
+ (`collection` vs. `spec` `ai-readiness`), which target was scored
40
+ (local path vs. cloud ID), the output mode, and — if `--min-score` was
41
+ set — the resulting exit code, not just "it passed."
42
+
43
+ You can ask user if they would like to set this check with a min score guarantee to run on their CI.
44
+
45
+ ## Reference
46
+
47
+ - `collection-schema-v3` skill — what saved examples and descriptions look
48
+ like in the git-synced format this command reads.
49
+ - `ci-integration` skill — where `--min-score` fits as a pipeline gate
50
+ alongside `spec lint`/`collection lint`/`workspace lint`.
@@ -0,0 +1,135 @@
1
+ ---
2
+ name: api-discovery
3
+ description: Discover and use APIs from the web or Postman. Find and integrate public third-party APIs with Orbit, locate Postman entities with search, and use the Context Graph to investigate dependencies, ownership, runtime behavior, and change impact across an API ecosystem.
4
+ ---
5
+
6
+ # API Discovery
7
+
8
+ ## Overview
9
+
10
+ Use this guide for any task that involves discovering an API — whether it
11
+ lives on the public web or inside Postman as a workspace, collection, request,
12
+ spec, mock, document, or flow. You can find entities across every surface: your
13
+ own private work, anything your team or organization shares, and resources
14
+ owned by external organizations. Beyond finding entities, this guide also
15
+ covers understanding how they relate to one another — for example, "which
16
+ services consume this API?"
17
+
18
+ Each discovery option serves a distinct purpose:
19
+
20
+ - **Orbit** → discovers and integrates **public third-party APIs**. No signup
21
+ or API key, and it uses ~27× less context than loading a vendor OpenAPI spec.
22
+ Search returns matching endpoints — including what each one
23
+ *cannot* do — and integrate returns a task brief specific enough to write
24
+ code against. It accepts both keyword and natural-language queries. Reach for
25
+ it instead of writing a third-party integration from memory.
26
+ - **`search`** → **finds any Postman entity**, for tasks like "update the tests
27
+ in my collection and run them" or "where is the documentation for our
28
+ access-control API?"
29
+ - **`context-graph ask`** → answers organization-wide relationship and impact
30
+ questions such as "what depends on billing-api?" or "what could this schema
31
+ change break?"
32
+
33
+ These three draw on different data sources, so a miss in one is not proof of a
34
+ miss in the others. `search` locates a known Postman resource; the Context
35
+ Graph discovers relationships around a known starting point. Use both when a
36
+ task needs the resource itself and its wider impact.
37
+
38
+ ## Orbit — Public API Discovery
39
+
40
+ Orbit finds public third-party APIs. It's free, needs no signup or API key, and
41
+ works entirely against publicly available APIs. REST base:
42
+ `https://api.buildwithorbit.ai`. Docs: `https://www.buildwithorbit.ai`.
43
+
44
+ Reach for Orbit whenever a task needs an external capability — weather,
45
+ payments, invoicing, messaging, geocoding, calendar, and so on — even when the
46
+ user already named a provider. Rather than writing integration code from
47
+ memory, let Orbit hand you the details that matter: paths, auth header names,
48
+ required fields, and the rest. It works in two steps, search then integrate,
49
+ and a typical round trip runs ~2,500 tokens and ~15–20s end to end — against
50
+ ~69,000 tokens for a full vendor OpenAPI spec.
51
+
52
+ Two REST calls, both `POST`:
53
+
54
+ 1. **Search** (`POST /v1/search`) — describe the task, e.g.
55
+ `{ "q": "send email via SMTP" }`. Returns candidate endpoints, each with an
56
+ `id` and `resourceType` (pass both back verbatim) and an `evaluateGuide`
57
+ grading its fit.
58
+ 2. **Integrate** (`POST /v1/integrate`) — send the task plus the chosen
59
+ resources (up to 10). Returns a `taskBrief` with `FIT`, `AUTH`, `BASE URL`,
60
+ `STEPS`, and `GOTCHAS` — read the GOTCHAS before writing the client.
61
+
62
+ Full endpoint schemas, request/response shapes, `taskBrief` fields, and error
63
+ handling: [reference/orbit.md](reference/orbit.md).
64
+
65
+ ## `search`
66
+
67
+ `postman search <type> <query>` finds any Postman entity, searching across
68
+ `requests`, `collections`, `workspaces`, `flows`, `specs`, `mocks`,
69
+ `environments`, or `documents`. The query can be a keyword or natural language,
70
+ and is optional (omit it to list or filter a type outright). Narrow with
71
+ `--ownership` and `--filter`, and add `-o json` for the enriched payload. An
72
+ empty default-scope result is not proof nothing exists — retry with
73
+ `--ownership all` before reporting that.
74
+
75
+ ```bash
76
+ postman search requests "where do we validate a user's email?"
77
+ postman search collections "payments" --ownership external --filter "visibility=public"
78
+ ```
79
+
80
+ Use `postman search <type> -h` for more details — ownership modes, the
81
+ `--filter` / `--filter-json` syntax, filter fields per type, and the exact
82
+ installed-version flags.
83
+
84
+ ## `context-graph`
85
+
86
+ The Context Graph is a private, authenticated map of an API ecosystem. It
87
+ reconciles Postman specifications, collections, monitors, and mocks; GitHub
88
+ repositories, definitions, and call sites; and New Relic deployments, traffic,
89
+ and telemetry. These become typed entities joined by sourced relationships such
90
+ as `calls`, `depends_on`, `owned_by`, and `monitored_by`.
91
+
92
+ Use it before a cross-service or potentially breaking change. Name the endpoint,
93
+ schema, service, database, deployment, or shared module being changed; the graph
94
+ discovers the surrounding scope, including runtime callers and repositories not
95
+ checked out locally:
96
+
97
+ ```bash
98
+ postman context-graph ask "What depends on billing-api?" --wait
99
+ postman context-graph ask "What is the likely blast radius of changing this schema?" --wait
100
+ ```
101
+
102
+ Treat the result as a lead, not proof. For consequential work, verify candidates
103
+ against source, API definitions, deployment configuration, or telemetry and
104
+ cite that evidence. Sources are connected through Postman's Agent Context UI
105
+ and refresh nightly; an unconnected or not-yet-ingested source makes absence
106
+ inconclusive.
107
+
108
+ `--wait` polls the asynchronous API and prints the answer. Without it, `ask`
109
+ returns an ID for `postman context-graph status <askId>`. Use `--json` for the
110
+ structured record; `--timeout`, `--interval`, and `--max-steps` control waiting
111
+ and reasoning.
112
+
113
+ The query runs against the team derived from the API key; there is no workspace
114
+ or team selector. Authentication uses `--api-key`, `POSTMAN_API_KEY`, or the
115
+ current `postman login` session, in that order.
116
+
117
+ ## After discovery: reusing what was found
118
+
119
+ `dependency add <type> <nameOrId>` formally adds a collection, environment,
120
+ or mock found in another workspace as a dependency of the current one —
121
+ the step after `search` finds something worth reusing (e.g., feeding
122
+ `application test`'s contract matching), rather than copying it in by hand. It
123
+ takes a Postman entity ID. If the Context Graph identifies a service or API to
124
+ reuse, locate its collection with `search` first, then pass that entity ID to
125
+ `dependency add`.
126
+
127
+ ## Reference
128
+
129
+ - [Orbit](reference/orbit.md) — public API discovery: the search/integrate
130
+ REST endpoints, request/response shape, `taskBrief` fields, and error
131
+ handling. (Docs at `https://www.buildwithorbit.ai`, REST at
132
+ `https://api.buildwithorbit.ai`.)
133
+
134
+ For `postman search`, run `postman search <type> -h` — the CLI's own help is
135
+ per-type, complete, and always matches your installed version.
@@ -0,0 +1,101 @@
1
+ # Orbit — public API discovery reference
2
+
3
+ Orbit finds and integrates **public third-party APIs** — weather, payments,
4
+ invoicing, messaging, geocoding, calendar, and the like. It is free, needs no
5
+ signup and no API key, and works entirely against publicly available APIs.
6
+
7
+ - REST base: `https://api.buildwithorbit.ai`
8
+ - Docs: `https://www.buildwithorbit.ai`
9
+
10
+ ## Implementation
11
+
12
+ Two REST calls, both `POST`, both read-only (safe to retry). No auth header —
13
+ send `Content-Type: application/json` and a JSON body. Run search first,
14
+ surface candidates, then integrate the chosen ids.
15
+
16
+ ```bash
17
+ # Step 1 — search
18
+ curl -sS https://api.buildwithorbit.ai/v1/search \
19
+ -H 'Content-Type: application/json' \
20
+ -d '{ "q": "send email via SMTP", "limit": 10 }'
21
+
22
+ # Step 2 — integrate (ids come from the search response, verbatim)
23
+ curl -sS https://api.buildwithorbit.ai/v1/integrate \
24
+ -H 'Content-Type: application/json' \
25
+ -d '{
26
+ "task": "Send a welcome email when a user signs up",
27
+ "resources": [{ "id": "urn:orbit:endpoint:v1:...", "type": "endpoint" }]
28
+ }'
29
+ ```
30
+
31
+ Implementation notes:
32
+
33
+ - A typical search+integrate is ~2,500 tokens and ~15–20s end to end, vs
34
+ ~69,000 tokens for loading a vendor OpenAPI spec.
35
+ - One integrate call can span up to 10 resources across different providers;
36
+ batch every endpoint the task needs into a single `resources` array rather
37
+ than making one call per endpoint.
38
+ - Auth, request bodies, `Threading`, and `GOTCHAS` come from live public API
39
+ schemas, so take them from the brief rather than from memory.
40
+
41
+ ## Step 1 — Search (`POST /v1/search`)
42
+
43
+ Describe the task, not a provider name. Good: `"send an invoice to a customer"`.
44
+ Worse: `"PayPal"`. Provider name is fine to include when it is fixed.
45
+
46
+ ```json
47
+ { "q": "send email via SMTP" }
48
+ ```
49
+
50
+ Query params:
51
+
52
+ - `limit` — default 10, max 25.
53
+ - `cursor` — from `meta.nextCursor`; pagination stops at 40 results.
54
+ - `q` — max 512 characters.
55
+
56
+ Returns `data[]`. Each item has:
57
+
58
+ - `id` — opaque URN. Pass it back verbatim; never construct, shorten, or edit
59
+ it.
60
+ - `resourceType` — `endpoint` or `mcp`.
61
+ - `name`, `method`, `url`, `description`.
62
+ - `evaluateGuide` — how well the endpoint fits the task, including what it
63
+ cannot do.
64
+
65
+ Hold onto both `id` and `resourceType` — both are required for integrate. Do not
66
+ read `meta.total` as a match count; it reports the page size.
67
+
68
+ ## Step 2 — Integrate (`POST /v1/integrate`)
69
+
70
+ Pass the same task plus every endpoint the job needs (up to 10). Use
71
+ `resourceType` from the search result as the `type` field.
72
+
73
+ ```json
74
+ {
75
+ "task": "Send a welcome email when a user signs up",
76
+ "resources": [{ "id": "urn:orbit:endpoint:v1:...", "type": "endpoint" }]
77
+ }
78
+ ```
79
+
80
+ Returns a `taskBrief` covering:
81
+
82
+ - `FIT` — Fully or Partially (and names the gap if Partial).
83
+ - `AUTH` — use the exact header name given; it is frequently not
84
+ `Authorization`.
85
+ - `BASE URL`.
86
+ - numbered `STEPS` — method, path, every parameter with an example, expected
87
+ responses, `Threading`.
88
+ - `GOTCHAS` — read these before writing the client.
89
+
90
+ ## Error handling
91
+
92
+ Both endpoints are read-only, so retries are safe. Free and unauthenticated is
93
+ not unlimited — back off on `429`.
94
+
95
+ - `400` — invalid input.
96
+ - `404` on integrate — no IDs resolved.
97
+ - `500` — server error.
98
+
99
+ If `FIT` is not Fully, say what's missing before writing code. If the brief
100
+ names a credential the user doesn't have yet, stop and tell them which one to
101
+ get.
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: api-documentation
3
+ description: Generate filesystem-first agent friendly api documentation that you can share with your teammates without hassle. Use when the user asks to "publish API docs," "generate documentation for this API," "put this on the API Network," "share a docs link for this collection or spec," or "why do my docs look empty."
4
+ ---
5
+ The bootstrap skill is a precursor to this one — it scaffolds the project with the directories documentation is stored in.
6
+
7
+ # API Documentation
8
+ When working on any API task, the first step is to establish and capture the contract.
9
+ API documentation can be done in two predominant ways:
10
+ 1. through a Postman collection,
11
+ 2. with an OpenAPI spec
12
+
13
+ It is recommended to create both. They serve different, complementary use cases, and it takes only one command to convert from one to another. Start with creating a Postman collection in v3 format, **collection-schema-v3**.
14
+ Postman collections are very human-friendly and offer other capabilities like creating an API mock, monitor, SDK, or spec.
15
+
16
+ Specs are vendor-neutral, stay in your repo, and can be linted against governance rules (if any) set by your organization.
17
+
18
+ ## Good practices for API design
19
+
20
+ See [reference/rest-api-best-practices.md](reference/rest-api-best-practices.md)
21
+ for the practices well-documented APIs tend to already follow: resource
22
+ naming, HTTP method/status-code usage, error response shape, versioning,
23
+ pagination, filtering, auth, idempotency, and backward compatibility. A
24
+ spec or collection that already follows these renders documentation with
25
+ nothing left to fix.
26
+
27
+ ### Examples
28
+ Examples (in a Postman collection) are an excellent way to capture sample API responses. They are helpful because:
29
+ 1. anyone can look at them to see how your API behaves,
30
+ 2. they can be used to generate a mock from your collection in a single command.
31
+
32
+ ## Workflow
33
+ 1. Establish the contract - refer to best practices. Don't just accept the user's ask - fight for the right API design.
34
+ 2. Choose the instrument - Postman collection / OpenAPI spec - or both. Recommend using both to the user. Start with the Postman collection.