diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index e02e23a..e236db9 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "postman", - "version": "1.3.1", + "version": "2.0.0", "description": "Full API lifecycle management for Claude Code. Sync collections, generate client code, discover APIs, run tests, create mocks, publish docs, and audit security. Powered by the Postman MCP Server.", "author": { "name": "Postman", @@ -19,6 +19,11 @@ "documentation", "security", "openapi", - "agent-ready" + "agent-ready", + "mocking", + "monitoring", + "ci", + "ai-readiness", + "flows" ] } diff --git a/.github/scripts/validate-frontmatter.py b/.github/scripts/validate-frontmatter.py index 37da84d..9e7a549 100755 --- a/.github/scripts/validate-frontmatter.py +++ b/.github/scripts/validate-frontmatter.py @@ -39,7 +39,8 @@ def validate_commands(root: Path) -> list[str]: errors = [] commands_dir = root / "commands" if not commands_dir.is_dir(): - return [f"{commands_dir}: Directory not found"] + # commands/ is optional — a plugin may be skill-only + return errors for f in sorted(commands_dir.glob("*.md")): text = f.read_text() @@ -88,7 +89,8 @@ def validate_agents(root: Path) -> list[str]: errors = [] agents_dir = root / "agents" if not agents_dir.is_dir(): - return [f"{agents_dir}: Directory not found"] + # agents/ is optional — a plugin may be skill-only + return errors required_fields = ["name", "description", "model", "allowed-tools"] diff --git a/.github/scripts/validate-structure.py b/.github/scripts/validate-structure.py index 6e6de42..dbce4f8 100755 --- a/.github/scripts/validate-structure.py +++ b/.github/scripts/validate-structure.py @@ -33,17 +33,14 @@ def main(): if not mcp_json.exists(): errors.append(".mcp.json: File not found") - # 3. Every commands/*.md must have frontmatter + # 3. commands/ is optional (a plugin may be skill-only); if present, every + # commands/*.md must have frontmatter commands_dir = root / "commands" if commands_dir.is_dir(): command_files = sorted(commands_dir.glob("*.md")) - if not command_files: - errors.append("commands/: No command files found") for f in command_files: if not has_frontmatter(f): errors.append(f"commands/{f.name}: Missing YAML frontmatter") - else: - errors.append("commands/: Directory not found") # 4. Every skills/*/ directory must have a SKILL.md skills_dir = root / "skills" @@ -60,17 +57,13 @@ def main(): else: errors.append("skills/: Directory not found") - # 5. Every agents/*.md must have frontmatter + # 5. agents/ is optional (a plugin may be skill-only); if present, every + # agents/*.md must have frontmatter agents_dir = root / "agents" if agents_dir.is_dir(): - agent_files = sorted(agents_dir.glob("*.md")) - if not agent_files: - errors.append("agents/: No agent files found") - for f in agent_files: + for f in sorted(agents_dir.glob("*.md")): if not has_frontmatter(f): errors.append(f"agents/{f.name}: Missing YAML frontmatter") - else: - errors.append("agents/: Directory not found") # 6. Check for stray markdown files in root (not README, CLAUDE, LICENSE, or examples) expected_root_md = {"README.md", "CLAUDE.md", "CHANGELOG.md", "LICENSE", "token-optimization-findings.md"} diff --git a/.mcp.json b/.mcp.json index c48b7c8..02a057c 100644 --- a/.mcp.json +++ b/.mcp.json @@ -5,8 +5,8 @@ "url": "https://mcp.postman.com/${POSTMAN_MCP_MODE:-mcp}", "headers": { "X-Source": "claude-code-plugin", - "X-Plugin-Version": "1.3.1", - "User-Agent": "postman-claude-code-plugin/1.3.1" + "X-Plugin-Version": "2.0.0", + "User-Agent": "postman-claude-code-plugin/2.0.0" } } } diff --git a/agents/readiness-analyzer.md b/agents/readiness-analyzer.md deleted file mode 100644 index 637ad0f..0000000 --- a/agents/readiness-analyzer.md +++ /dev/null @@ -1,227 +0,0 @@ ---- -name: API Readiness Analyzer -description: Analyze any API or OpenAPI spec for AI agent compatibility — 48 checks across 8 pillars, with scoring and fix recommendations. Use when the user asks whether an API is agent-ready or wants it scanned, scored, or improved for AI agents. -model: sonnet -allowed-tools: Read, Edit, Write, Glob, Grep, Bash, mcp__postman__getWorkspaces, mcp__postman__getAllSpecs, mcp__postman__getSpecDefinition, mcp__postman__createSpec, mcp__postman__generateCollection, mcp__postman__getAsyncSpecTaskStatus, mcp__postman__getGeneratedCollectionSpecs, mcp__postman__createEnvironment, mcp__postman__createMock, mcp__postman__runCollection, mcp__postman__publishDocumentation ---- - -# API Readiness Analyzer - -## 1. Role - -You are an opinionated API analyst. You evaluate APIs for AI agent compatibility using 48 checks across 8 pillars. You don't sugarcoat results. If an API scores 45%, you say so and explain exactly what's broken. - -Your job is to answer one question: **Can an AI agent reliably use this API?** - -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. You help developers close the gap. - ---- - -## 2. The 8 Pillars - -| Pillar | What It Measures | Why Agents Care | -|--------|-----------------|-----------------| -| **Metadata** | operationIds, summaries, descriptions, tags | Agents need to discover and select the right endpoint | -| **Errors** | Error schemas, codes, messages, retry guidance | Agents need to self-heal when things go wrong | -| **Introspection** | Parameter types, required fields, enums, examples | Agents need to construct valid requests without guessing | -| **Naming** | Consistent casing, RESTful paths, HTTP semantics | Agents need predictable patterns to reason about | -| **Predictability** | Response schemas, pagination, date formats | Agents need to parse responses reliably | -| **Documentation** | Auth docs, rate limits, external links | Agents need context humans get from reading docs | -| **Performance** | Rate limit docs, cache headers, bulk endpoints, async patterns | Agents need to operate within constraints | -| **Discoverability** | OpenAPI version, server URLs, contact info | Agents need to find and connect to the API | - -### Scoring - -Each check has a severity level with weights: -- **Critical** (4x) — Blocks agent usage entirely -- **High** (2x) — Causes frequent agent failures -- **Medium** (1x) — Degrades agent performance -- **Low** (0.5x) — Nice-to-have improvements - -**Agent Ready = score of 70% or higher with zero critical failures.** - ---- - -## 3. The 48 Checks - -### Metadata (META) -1. **META_001** Every operation has an `operationId` (Critical) -2. **META_002** Every operation has a `summary` (High) -3. **META_003** Every operation has a `description` (Medium) -4. **META_004** All parameters have descriptions (Medium) -5. **META_005** Operations are grouped with tags (Medium) -6. **META_006** Tags have descriptions (Low) - -### Errors (ERR) -7. **ERR_001** 4xx error responses defined for each endpoint (Critical) -8. **ERR_002** Error response schemas include a machine-readable error identifier and human-readable message (Critical) -9. **ERR_003** 5xx error responses defined (High) -10. **ERR_004** 429 Too Many Requests response defined (High) -11. **ERR_005** Error examples provided (Medium) -12. **ERR_006** Retry-After header documented for 429/503 (Medium) - -### Introspection (INTRO) -13. **INTRO_001** All parameters have `type` defined (Critical) -14. **INTRO_002** Required fields are marked (Critical) -15. **INTRO_003** Enum values used for constrained fields (High) -16. **INTRO_004** String parameters have `format` where applicable (Medium) -17. **INTRO_005** Request body examples provided (High) -18. **INTRO_006** Response body examples provided (Medium) - -### Naming (NAME) -19. **NAME_001** Consistent casing in paths (kebab-case preferred) (High) -20. **NAME_002** RESTful path patterns (nouns, not verbs) (High) -21. **NAME_003** Correct HTTP method semantics (Medium) -22. **NAME_004** Consistent pluralization in resource names (Medium) -23. **NAME_005** Consistent property naming convention (Medium) -24. **NAME_006** No abbreviations in public-facing names (Low) - -### Predictability (PRED) -25. **PRED_001** All responses have schemas defined (Critical) -26. **PRED_002** Consistent response envelope pattern (High) -27. **PRED_003** Pagination documented for list endpoints (High) -28. **PRED_004** Consistent date/time format (ISO 8601) (Medium) -29. **PRED_005** Consistent ID format across resources (Medium) -30. **PRED_006** Nullable fields explicitly marked (Medium) - -### Documentation (DOC) -31. **DOC_001** Authentication documented in security schemes (Critical) -32. **DOC_002** Auth requirements per endpoint (High) -33. **DOC_003** Rate limits documented (High) -34. **DOC_004** API description provides overview (Medium) -35. **DOC_005** External documentation links provided (Low) -36. **DOC_006** Terms of service and contact info (Low) - -### Performance (PERF) -37. **PERF_001** Rate limit headers documented in response schemas (High) -38. **PERF_002** Cache headers documented in response schemas (Medium) -39. **PERF_003** Compression support noted (Medium) -40. **PERF_004** Bulk/batch endpoints available for high-volume operations (Low) -41. **PERF_005** Partial response support (fields parameter) documented (Low) -42. **PERF_006** Webhook/async patterns documented for long-running operations (Low) - -### Discoverability (DISC) -43. **DISC_001** OpenAPI 3.0+ used (High) -44. **DISC_002** Server URLs defined (Critical) -45. **DISC_003** Multiple environments documented (staging, prod) (Medium) -46. **DISC_004** API version in URL or header (Medium) -47. **DISC_005** CORS documented (Low) -48. **DISC_006** Health check endpoint exists (Low) - ---- - -## 4. Workflow - -### Step 0: Pre-flight Check - -1. **Find the spec** — Look for OpenAPI files in the project (`**/openapi.{json,yaml,yml}`, `**/swagger.{json,yaml,yml}`, `**/*-api.{json,yaml,yml}`). If none found, ask the user. -2. **Validate the spec** — Confirm it's parseable YAML/JSON with at least `info` and `paths`. If invalid, report errors and stop. -3. **Check MCP availability** — Try calling `getWorkspaces` via Postman MCP. - - If MCP is available: full analysis + Postman push capabilities - - If MCP is not available: static spec analysis only. Tell the user: "Postman MCP isn't configured. I can still analyze and fix your spec. Run `/postman:setup` to push results to Postman." - -### Step 1: Discover - -Find specs in the project and from Postman (if MCP available): -- Local files: `**/openapi.{json,yaml,yml}`, `**/swagger.*`, `**/*-api.*` -- Postman: `getAllSpecs` + `getSpecDefinition` - -If multiple specs found, list them and ask which to analyze. - -### Step 2: Analyze - -Read the spec and evaluate all 48 checks. For each check: -1. Examine the relevant parts of the spec -2. Count passing and failing items -3. Assign pass/fail/partial status -4. Calculate weighted score - -**Scoring formula:** -- Per check: `weight * (passing_items / total_items)` (skip N/A checks) -- Per pillar: `sum(weighted_scores) / sum(applicable_weights) * 100` -- Overall: `sum(all_weighted_scores) / sum(all_applicable_weights) * 100` - -### Step 3: Present Results - -**Overall Score and Verdict:** -``` -Score: 67/100 -Verdict: NOT AGENT-READY (need 70+ with no critical failures) -``` - -**Pillar Breakdown:** -``` -Metadata: ████████░░ 82% -Errors: ████░░░░░░ 41% ← Problem -Introspection: ███████░░░ 72% -Naming: █████████░ 91% -Predictability: ██████░░░░ 63% ← Problem -Documentation: ███░░░░░░░ 35% ← Problem -Performance: █████░░░░░ 52% -Discoverability: ████████░░ 80% -``` - -**Top 5 Priority Fixes** (sorted by impact): -For each fix, include: -1. The check ID and what failed -2. Why it matters for agents (concrete failure scenario) -3. How to fix it (specific code example from their spec) - -### Step 4: Offer Next Steps - -1. **"Want me to fix these?"** — Walk through fixes one by one, editing the spec directly -2. **"Run again after fixes"** — Re-analyze and show score improvement -3. **"Generate full report"** — Save a detailed markdown report to the project -4. **"Export to Postman"** — Push improved spec to Postman, set up collection + environment + mock + docs - ---- - -## 5. Fixing Issues - -When the user says "fix these" or "help me improve my score": - -1. Start with highest-impact fix (highest severity times most endpoints affected) -2. Read the relevant section of their spec -3. Show the specific change needed with before/after -4. Make the edit (with user approval) -5. Move to the next fix -6. After all fixes, re-analyze to show the new score - ---- - -## 6. Postman MCP Integration - -After analysis and fixes, if Postman MCP is available: - -1. **Push spec:** `createSpec` to store the improved spec -2. **Generate collection:** `generateCollection` from the spec (async, poll for completion) -3. **Create environment:** `createEnvironment` with base_url and auth variables -4. **Create mock:** `createMock` for frontend development -5. **Run tests:** `runCollection` to validate -6. **Publish docs:** `publishDocumentation` to make docs public - -From "broken API" to "fully operational Postman workspace" in one session. - ---- - -## 7. Tone - -- **Direct.** "Your API scores 45%. That's not great. Here's what's dragging it down." -- **Specific.** Always point to the exact check, endpoint, and fix. -- **Practical.** Show the code change, not a REST theory lecture. -- **Encouraging when earned.** "Your naming is solid at 91%. The errors pillar is what's killing you." - ---- - -## 8. Quick Reference - -| User Says | What To Do | -|-----------|------------| -| "Is my API agent-ready?" | Discover specs, run analysis, present score | -| "Scan my project" | Find all specs, summarize each | -| "What's wrong?" | Show top 5 failures sorted by impact | -| "Fix it" | Walk through fixes one by one, edit spec | -| "Run again" | Re-analyze, show before/after comparison | -| "Generate report" | Save detailed markdown report to project | -| "How do I get to 90%?" | Calculate gap, show exactly which fixes get there | -| "Export to Postman" | Push spec, generate collection, set up workspace | diff --git a/commands/deploy-flow.md b/commands/deploy-flow.md deleted file mode 100644 index 99df80d..0000000 --- a/commands/deploy-flow.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -description: Deploy a Postman Flow so it becomes triggerable, proposing and confirming a trigger path -allowed-tools: Bash, Read ---- - -Deploy a Postman Flow using the Postman CLI. Follow the `deploy-flow` skill. - -## Inputs (from the user's message) -- The flow (a 24-char ID, or a name to resolve via `list-flows`) -- Optionally a desired trigger path and whether auth is required - -## Steps -1. Resolve the flow ID (use `list-flows` if given a name; ask for the workspace if unknown). -2. Propose a trigger path derived from the flow name (e.g. "Checkout" → `/checkout`) and **confirm the path + the deploy action** with the user — deploy is mutating and MUST NOT run without explicit confirmation. -3. Show the command, then run it after confirmation: - ```bash - POSTMAN_CLI_SOURCE=claude-code-plugin postman flows deploy --path /checkout - ``` -4. Report the **Trigger URL** and whether the **trigger is enabled**. If it's off, offer `postman flows update --trigger on` (confirm first). -5. If this was part of a deploy-then-trigger request, hand back to `trigger-flow` to run it. - -Always prefix CLI calls with `POSTMAN_CLI_SOURCE=claude-code-plugin`. Reuse existing `postman login` credentials — never authenticate twice. diff --git a/commands/generate-spec.md b/commands/generate-spec.md deleted file mode 100644 index 032456b..0000000 --- a/commands/generate-spec.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -description: Generate or update an OpenAPI spec from your codebase ---- - -Generate or update an OpenAPI 3.0 specification by analyzing API routes in your codebase. - -## Step 1: Check for Existing Spec - -```bash -ls postman/specs/**/*.yaml postman/specs/**/*.yml postman/specs/**/*.json 2>/dev/null -ls openapi.yaml openapi.yml swagger.yaml swagger.yml 2>/dev/null -``` - -If a spec exists, read it to understand current state. You'll update it rather than replace it. - -## Step 2: Discover API Endpoints - -Scan the project for route definitions based on the framework: - -- **Express/Node**: `app.get()`, `router.post()`, `@Get()` (NestJS) -- **Python**: `@app.route()`, `@router.get()` (FastAPI), `path()` (Django) -- **Go**: `http.HandleFunc()`, `r.GET()` (Gin/Echo) -- **Java**: `@GetMapping`, `@PostMapping`, `@RequestMapping` -- **Ruby**: `get`, `post`, `resources` in routes.rb - -Read the route files and extract: methods, paths, parameters, request bodies, response schemas, auth requirements. - -## Step 3: Generate or Update the Spec - -Write a valid OpenAPI 3.0.3 YAML spec including: -- `info` with title, version, description -- `servers` with local dev URL -- `paths` with all discovered endpoints -- `components/schemas` with models derived from code (types, models, structs) -- `components/securitySchemes` if auth is used - -**When updating**: Add new endpoints, update changed ones, remove endpoints no longer in code. Preserve existing descriptions and examples. - -**When creating**: Write to `postman/specs/openapi.yaml`. - -## Step 4: Validate - -```bash -postman spec lint ./postman/specs/openapi.yaml -``` - -Fix any validation errors and re-run until clean. - -## Step 5: Report - -Show what was created or changed: -- Endpoints documented (count and list) -- Schemas defined -- Changes from previous spec (if updating) -- Validation result diff --git a/commands/get-flow-run.md b/commands/get-flow-run.md deleted file mode 100644 index e424c6d..0000000 --- a/commands/get-flow-run.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -description: Inspect a Postman Flow run by its Run ID — per-block logs, failing block, and status -allowed-tools: Bash, Read ---- - -Inspect a specific Postman Flow run using the Postman CLI. Follow the `get-flow-run` skill. - -## Inputs (from the user's message) -- The Run ID (the `x-run-id` that `trigger-flow` reported; ask if unknown) -- Optionally a block ID to focus on - -## Steps -1. Take the Run ID. -2. Run a summary, then add `--logs` for detail: - ```bash - POSTMAN_CLI_SOURCE=claude-code-plugin postman flows get-run --run-id - POSTMAN_CLI_SOURCE=claude-code-plugin postman flows get-run --run-id --logs - ``` - Narrow to a block with `--filter `. -3. Report **which block failed and why** and the **run status**. - -Read-only: no confirmation needed. Prefix CLI calls with `POSTMAN_CLI_SOURCE=claude-code-plugin`. Reuse existing `postman login` credentials. diff --git a/commands/list-flows.md b/commands/list-flows.md deleted file mode 100644 index febdaf4..0000000 --- a/commands/list-flows.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -description: List Postman Flows in a workspace and resolve a flow name to its 24-character ID -allowed-tools: Bash, Read ---- - -List Postman Flows in a workspace using the Postman CLI. Follow the `list-flows` skill. - -## Inputs (from the user's message) -- The workspace ID (ask if unknown) -- Optionally a name/pattern to filter by - -## Steps -1. Ensure you have a workspace ID; ask which workspace if not. -2. Run: - ```bash - POSTMAN_CLI_SOURCE=claude-code-plugin postman flows list --workspace - ``` - Narrow with `--filter ""` when resolving a specific flow; use `--sort name` / `--paginate` as needed. -3. Report flow **names + IDs** (and recent status where shown). When resolving a name for another action, return the single matching ID, or present candidates and ask the user to choose on multiple matches — never guess. - -Read-only: no confirmation needed. Prefix CLI calls with `POSTMAN_CLI_SOURCE=claude-code-plugin`. Reuse existing `postman login` credentials. diff --git a/commands/run-collection.md b/commands/run-collection.md deleted file mode 100644 index b344a1f..0000000 --- a/commands/run-collection.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -description: Run Postman collection tests using the CLI ---- - -Run Postman collection tests to verify your API endpoints. - -## Step 1: Find Collections and IDs - -List collection folders and look up their cloud IDs: - -```bash -ls postman/collections/ -cat .postman/resources.yaml -``` - -The `cloudResources.collections` section maps local collection paths to cloud IDs. - -If no collections found, tell the user and stop. -If one collection, use it directly. -If multiple, list them and ask which to run. - -## Step 2: Run the Collection - -Run by **collection ID** (from `.postman/resources.yaml`): - -```bash -postman collection run -``` - -Common options: -```bash -# Stop on first failure -postman collection run --bail - -# With request timeout -postman collection run --timeout-request 10000 - -# With environment -postman collection run -e ./postman/environments/.json - -# Override environment variable -postman collection run --env-var "base_url=http://localhost:3000" -``` - -## Step 3: Parse and Report Results - -Parse the CLI output for pass/fail counts, failed test names, error messages, and status codes. - -## Step 4: Handle Failures - -If tests fail: -1. Analyze error messages -2. Read relevant source code -3. Suggest fixes -4. After fixes, re-run to verify diff --git a/commands/send-request.md b/commands/send-request.md deleted file mode 100644 index 06e8c48..0000000 --- a/commands/send-request.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -description: Send HTTP requests using Postman CLI ---- - -Send an HTTP request using the Postman CLI. Ask the user what URL and method they want, or detect it from context. - -## Step 1: Determine Request Details - -Ask the user for: -- URL to send the request to -- HTTP method (default: GET) -- Any headers, body, or auth needed - -If the user wants to send a request from a collection, find collection folders in `postman/collections/` and read the `*.request.yaml` files to extract method and URL. Collections use the v3 folder format. - -## Step 2: Build and Execute - -```bash -postman request "" -``` - -**With headers:** add `-H "Header: value"` -**With body:** add `-d '{"key": "value"}'` -**With bearer auth:** add `--auth-bearer-token ""` -**With API key:** add `--auth-apikey-key "" --auth-apikey-value ""` -**With basic auth:** add `--auth-basic-username "" --auth-basic-password ""` -**With environment:** add `-e ./postman/environments/.json` - -Always show the exact command before running it. - -## Step 3: Report Results - -Parse the response and report status code, response time, and body. Suggest fixes for errors (auth issues, connection problems, invalid URLs). diff --git a/commands/trigger-flow.md b/commands/trigger-flow.md deleted file mode 100644 index 6a1565c..0000000 --- a/commands/trigger-flow.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -description: Trigger (run) a deployed Postman Flow with inputs, and deploy-then-trigger it if it isn't deployed yet -allowed-tools: Bash, Read ---- - -Trigger a deployed Postman Flow from natural language, using the Postman CLI. Follow the `trigger-flow` skill. - -## Inputs (from the user's message) -- The flow (a 24-char ID, or a name to resolve via `list-flows`) -- Any inputs / query params / headers / scenario -- The workspace ID (ask if a name needs resolving and you don't have it) - -## Steps -1. Resolve the flow ID (use `list-flows` if given a name; disambiguate multiple matches; ask for the workspace if unknown). -2. Build the flags from natural language: `-i k=v`, `-q k=v`, `--headers k=v`, `-s ""`. -3. Show the command, then run it: - ```bash - POSTMAN_CLI_SOURCE=claude-code-plugin postman flows trigger -i amount=4200 - ``` -4. Report the **Run ID**, **HTTP status**, and **response body**. -5. If not deployed → explain and **offer to deploy** (via `deploy-flow`, explicit confirmation required), then re-trigger. If the trigger is disabled → offer `postman flows update --trigger on` (confirm), then trigger. -6. On a non-2xx response → surface status + body and offer `get-flow-run --run-id ` for per-block detail. - -Always prefix CLI calls with `POSTMAN_CLI_SOURCE=claude-code-plugin`. Reuse existing `postman login` credentials — never authenticate twice. Confirm before any mutating action (deploy, enable trigger). diff --git a/examples/sample-readiness-report.md b/examples/sample-readiness-report.md deleted file mode 100644 index 533a3dc..0000000 --- a/examples/sample-readiness-report.md +++ /dev/null @@ -1,53 +0,0 @@ -# API Readiness Analysis: Pet Store API - -**Date:** 2026-02-10 -**Spec:** petstore-openapi.yaml -**Score:** 67/100 -**Verdict:** NOT AGENT-READY (need 70+ with no critical failures) - -## Pillar Scores - -| Pillar | Score | Status | -|--------|-------|--------| -| Metadata | 82% | Good | -| Errors | 41% | Critical issues | -| Introspection | 72% | Acceptable | -| Naming | 91% | Excellent | -| Predictability | 63% | Needs work | -| Documentation | 35% | Critical issues | -| Performance | 52% | Needs work | -| Discoverability | 80% | Good | - -## Top 5 Priority Fixes - -### 1. Missing error response schemas (ERR_001) — Critical -**Affects:** 12 of 15 endpoints -**Impact:** Agents hitting errors have no idea what the response body looks like. -**Fix:** Add 4xx/5xx response schemas with error code, message, and details fields. - -### 2. No rate limit documentation (DOC_003) — High -**Affects:** All endpoints -**Impact:** Agents will hammer the API with no awareness of limits. -**Fix:** Add rate limit info to API description and X-RateLimit headers to responses. - -### 3. Missing request body examples (INTRO_005) — High -**Affects:** 8 POST/PUT endpoints -**Impact:** Agents must construct request bodies from scratch with no reference. -**Fix:** Add example values for each request body schema. - -### 4. No pagination pattern (PRED_003) — Medium -**Affects:** 3 list endpoints -**Impact:** Agents will try to load entire datasets in one call. -**Fix:** Add limit/offset or cursor-based pagination with Link headers. - -### 5. Missing parameter descriptions (META_004) — Medium -**Affects:** 22 of 45 parameters -**Impact:** Agents can't determine what values are valid for each parameter. -**Fix:** Add description field to all parameters. - -## After Fixes - -Re-running analysis after applying all 5 fixes: -- **New Score:** 89/100 -- **Verdict:** AGENT-READY -- **Improvement:** +22 points diff --git a/skills/agent-ready-apis/SKILL.md b/skills/agent-ready-apis/SKILL.md deleted file mode 100644 index 96f7c53..0000000 --- a/skills/agent-ready-apis/SKILL.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -name: agent-ready-apis -description: Knowledge about AI agent API compatibility. Use when user asks about API readiness, agent compatibility, or wants to improve their API for AI consumption. -user-invocable: false ---- - -# Agent-Ready APIs - -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. - -## When to Suggest the Analyzer - -If the user mentions any of these, suggest running the readiness-analyzer agent: -- "Is my API agent-ready?" -- "Can AI agents use my API?" -- "Scan my API" / "Analyze my spec" -- "What's wrong with my API for AI?" -- "How agent-friendly is my API?" -- "Improve my API for AI agents" - -## What Gets Evaluated - -The analyzer checks 48 items across 8 pillars: - -| Pillar | What It Measures | -|--------|-----------------| -| Metadata | operationIds, summaries, descriptions, tags | -| Errors | Error schemas, codes, messages, retry guidance | -| Introspection | Parameter types, required fields, enums, examples | -| Naming | Consistent casing, RESTful paths, HTTP semantics | -| Predictability | Response schemas, pagination, date formats | -| Documentation | Auth docs, rate limits, external links | -| Performance | Rate limit headers, cache, bulk endpoints, async patterns | -| Discoverability | OpenAPI version, server URLs, contact info | - -## Scoring - -- **Critical checks (4x weight):** Blocks agent usage entirely -- **High checks (2x weight):** Causes frequent agent failures -- **Medium checks (1x weight):** Degrades agent performance -- **Low checks (0.5x weight):** Nice-to-have improvements - -**Agent Ready = score of 70% or higher with zero critical failures.** - -## Interpreting Results - -- **90-100%:** Excellent. Agents can use this API reliably. -- **70-89%:** Agent-ready. Minor improvements possible. -- **50-69%:** Not agent-ready. Key issues need fixing. -- **Below 50%:** Significant work needed. Focus on critical failures first. - -See `pillars.md` in this skill folder for the full check reference. diff --git a/skills/agent-ready-apis/pillars.md b/skills/agent-ready-apis/pillars.md deleted file mode 100644 index f74b15b..0000000 --- a/skills/agent-ready-apis/pillars.md +++ /dev/null @@ -1,116 +0,0 @@ -# The 8 Pillars of Agent Readiness - -## Metadata (META) - -| Check | Description | Severity | -|-------|-------------|----------| -| META_001 | Every operation has an `operationId` | Critical | -| META_002 | Every operation has a `summary` | High | -| META_003 | Every operation has a `description` | Medium | -| META_004 | All parameters have descriptions | Medium | -| META_005 | Operations are grouped with tags | Medium | -| META_006 | Tags have descriptions | Low | - -**Why agents care:** Agents need to discover and select the right endpoint from a list. Without operationIds, agents can't reliably reference endpoints. Without summaries and descriptions, agents can't determine which endpoint matches their goal. - -## Errors (ERR) - -| Check | Description | Severity | -|-------|-------------|----------| -| ERR_001 | 4xx error responses defined for each endpoint | Critical | -| ERR_002 | Error schemas include machine-readable identifier and human-readable message | Critical | -| ERR_003 | 5xx error responses defined | High | -| ERR_004 | 429 Too Many Requests response defined | High | -| ERR_005 | Error examples provided | Medium | -| ERR_006 | Retry-After header documented for 429/503 | Medium | - -**Why agents care:** Agents need to self-heal when things go wrong. Without structured error schemas, an agent hitting a 400 has no idea how to parse the error or recover. Without 429 documentation, agents hammer APIs until blocked. - -## Introspection (INTRO) - -| Check | Description | Severity | -|-------|-------------|----------| -| INTRO_001 | All parameters have `type` defined | Critical | -| INTRO_002 | Required fields are marked | Critical | -| INTRO_003 | Enum values used for constrained fields | High | -| INTRO_004 | String parameters have `format` where applicable | Medium | -| INTRO_005 | Request body examples provided | High | -| INTRO_006 | Response body examples provided | Medium | - -**Why agents care:** Agents need to construct valid requests without guessing. Missing types force agents to guess formats. Missing required field markers lead to validation errors. Missing examples mean agents build request bodies from scratch with no reference. - -## Naming (NAME) - -| Check | Description | Severity | -|-------|-------------|----------| -| NAME_001 | Consistent casing in paths (kebab-case preferred) | High | -| NAME_002 | RESTful path patterns (nouns, not verbs) | High | -| NAME_003 | Correct HTTP method semantics | Medium | -| NAME_004 | Consistent pluralization in resource names | Medium | -| NAME_005 | Consistent property naming convention | Medium | -| NAME_006 | No abbreviations in public-facing names | Low | - -**Why agents care:** Agents need predictable patterns to reason about. Inconsistent naming means agents can't predict URL patterns, leading to wrong endpoint calls. Verb-based paths break REST mental models that agents rely on. - -## Predictability (PRED) - -| Check | Description | Severity | -|-------|-------------|----------| -| PRED_001 | All responses have schemas defined | Critical | -| PRED_002 | Consistent response envelope pattern | High | -| PRED_003 | Pagination documented for list endpoints | High | -| PRED_004 | Consistent date/time format (ISO 8601) | Medium | -| PRED_005 | Consistent ID format across resources | Medium | -| PRED_006 | Nullable fields explicitly marked | Medium | - -**Why agents care:** Agents need to parse responses reliably. Missing schemas mean agents can't validate what they receive. No pagination documentation means agents try to load entire datasets in one call. Inconsistent date formats cause parsing failures. - -## Documentation (DOC) - -| Check | Description | Severity | -|-------|-------------|----------| -| DOC_001 | Authentication documented in security schemes | Critical | -| DOC_002 | Auth requirements per endpoint | High | -| DOC_003 | Rate limits documented | High | -| DOC_004 | API description provides overview | Medium | -| DOC_005 | External documentation links provided | Low | -| DOC_006 | Terms of service and contact info | Low | - -**Why agents care:** Agents need context that humans get from reading docs. Without auth documentation, agents can't authenticate. Without rate limit documentation, agents have no awareness of usage constraints. - -## Performance (PERF) - -| Check | Description | Severity | -|-------|-------------|----------| -| PERF_001 | Rate limit headers documented (X-RateLimit-*) | High | -| PERF_002 | Cache headers documented (ETag, Cache-Control) | Medium | -| PERF_003 | Compression support noted | Medium | -| PERF_004 | Bulk/batch endpoints for high-volume operations | Low | -| PERF_005 | Partial response support (fields parameter) | Low | -| PERF_006 | Webhook/async patterns for long-running operations | Low | - -**Why agents care:** Agents need to operate within constraints. Without rate limit headers in responses, agents can't self-throttle. Without cache headers, agents re-fetch data unnecessarily. Without bulk endpoints, agents make hundreds of individual calls. - -## Discoverability (DISC) - -| Check | Description | Severity | -|-------|-------------|----------| -| DISC_001 | OpenAPI 3.0+ used | High | -| DISC_002 | Server URLs defined | Critical | -| DISC_003 | Multiple environments documented (staging, prod) | Medium | -| DISC_004 | API version in URL or header | Medium | -| DISC_005 | CORS documented | Low | -| DISC_006 | Health check endpoint exists | Low | - -**Why agents care:** Agents need to find and connect to the API. Missing server URLs mean agents have no idea where to send requests. Older spec formats (Swagger 2.0) have less machine-readable information for agents to work with. - -## Scoring Formula - -For each check: -- If N/A (e.g., no list endpoints for pagination check): exclude from scoring -- If applicable: `weight * (passing_items / total_items)` - -Pillar score: `sum(weighted_scores) / sum(applicable_weights) * 100` -Overall score: `sum(all_weighted_scores) / sum(all_applicable_weights) * 100` - -Severity weights: Critical = 4, High = 2, Medium = 1, Low = 0.5 diff --git a/skills/ai-readiness/SKILL.md b/skills/ai-readiness/SKILL.md new file mode 100644 index 0000000..5859e6f --- /dev/null +++ b/skills/ai-readiness/SKILL.md @@ -0,0 +1,48 @@ +--- +name: ai-readiness +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`. +--- + +# AI Readiness + +## Overview + +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. + +Two ways to run this check, same rubric family, different target — pick by what exists: + +- `collection ai-readiness ` scores a Postman collection + — by cloud ID, local file path, or a `postman/collections/` + local-mode directory. +- `spec ai-readiness ` scores an OpenAPI specification directly — by + cloud ID or local file path — with no collection involved at all. + +## Scoring + +The command computes and prints the score itself — read the fields it +gives you, don't recompute them: + +- **`readiness`** (score 0-100 + bucket) is the headline number. Buckets, + low to high: **Limited → Fair → Good → Excellent**. +- **`confidence`** (`high`/`medium`/`low`) says how many signals it + could actually measure vs. had to mark `unknown` — a data-quality + caveat, not part of the score. + +## Interpreting Results + +Report the bucket, score, and confidence the command actually printed +— don't infer a percentage band. Doc coverage is a modifier via its +adjustment, not a separate gate; call it out by name when it's `low`, +since recommendations flag that first. Also state which verb ran +(`collection` vs. `spec` `ai-readiness`), which target was scored +(local path vs. cloud ID), the output mode, and — if `--min-score` was +set — the resulting exit code, not just "it passed." + +You can ask user if they would like to set this check with a min score guarantee to run on their CI. + +## Reference + +- `collection-schema-v3` skill — what saved examples and descriptions look + like in the git-synced format this command reads. +- `ci-integration` skill — where `--min-score` fits as a pipeline gate + alongside `spec lint`/`collection lint`/`workspace lint`. diff --git a/skills/api-discovery/SKILL.md b/skills/api-discovery/SKILL.md new file mode 100644 index 0000000..945a095 --- /dev/null +++ b/skills/api-discovery/SKILL.md @@ -0,0 +1,94 @@ +--- +name: api-discovery +description: Finds what APIs, collections, specs, or requests already exist before building something new, and answers questions about how they relate. Use when the user asks "does an API for X already exist," "what depends on this service," "what does this API do," or before scaffolding anything that might already have a Postman equivalent. Covers `postman search`, `postman context-graph`, and `postman context instructions discovery`. Reach for `search` when you know roughly what you're looking for by name; reach for the Context Graph when the question is about relationships, not names. +--- + +# API Discovery + +## Overview + +Two unconnected datasets, so pick by data source, not question shape: + +- **`search` / `context`** → **Postman-authored artifacts** someone saved + in Postman (collections, requests, specs, mocks, workspaces). Matches + text; doesn't reason. "Does something named/shaped like X exist?" +- **`context-graph ask`** → a separately-populated **engineering service + graph** (built from repo/traffic scanning, not Postman content) — + natural-language Q&A over discovered services and the dependency edges + between them. "What depends on billing-api?" — architecture questions + `search` structurally can't answer, since there's no keyword for a + dependency edge. + +A miss in one says nothing about the other (see Critical Rule 1) — never +fall back to the Context Graph just because a `search` came back empty, or +vice versa. + +## `search` + +`search ` where type is `requests`, `collections`, +`workspaces`, `flows`, `specs`, `mocks`, `environments`, or `documents`. +Default `--ownership organization` only searches inside your org — pass +`external` or `all` before concluding "no API for this exists," since a +partner or public API published outside the org is invisible at the +default scope. `--filter "method=POST AND workspaceId=ws-123"` narrows +further; see [reference/search_filters.md](reference/search_filters.md) for +the full filter field and operator syntax per element type. + +## `context-graph` + +`context-graph ask "" --wait` is the one to reach for +interactively — it blocks and prints the answer. Without `--wait`, `ask` +returns an id immediately and `status ` checks on it later (exit +code 3 while still running) — useful for a question expected to take a +while, or from a script polling on its own cadence. The query runs against +the team derived from the API key; there's no workspace/team selection. +`--max-steps` caps how much reasoning the service does per question. + +The answer is generated, not retrieved verbatim — verify with a re-ask or +narrower query before acting on it for anything consequential (Critical +Rule 3), the same way any AI-generated claim gets checked before it drives +a decision. + +## `context instructions discovery` + +Postman ships its own prescribed discovery workflow for AI coding agents — +`postman context instructions discovery` prints it. Read this before +building a custom discovery flow out of `search`/`context` primitives; it's +Postman's own recommended sequence (search/context only, no +`context-graph`), not a blank slate to reinvent. + +## After discovery: reusing what was found + +`dependency add ` formally adds a collection, environment, +or mock found in another workspace as a dependency of the current one — +the step after `search`/`context` finds something worth reusing (e.g., +feeding `application test`'s contract matching), rather than copying it in +by hand. It takes a Postman entity ID, so it only follows a `search`/ +`context` result — a `context-graph` finding names a service, not an ID; +go find that service's collection via `search` first. + +## Critical Rules + +1. **`context-graph` and `search`/`context` don't share a dataset** (see + Overview) — check an absence against its own source, never the other + tool, before reporting it to the user. +2. **An empty default-scope `search` is not proof nothing exists.** Retry + with `--ownership all` before reporting "no API for this" to the user. +3. **A Context Graph answer is generated reasoning, not a database read.** + Verify it against a concrete source before treating it as fact, + especially for anything the user will act on. +4. **`search`, `context-graph`, and `context` are Beta or recently added + surfaces.** Re-run `-h` before trusting a flag name here if the installed + CLI is newer than this file assumes — these are the commands most likely + to have changed since this was written. + +## Verification + +State which tool actually answered the question (search vs. Context Graph) +and at what `--ownership` scope or with what `--max-steps`/query — a +discovery answer is only as trustworthy as the scope it ran at. + +## Reference + +- [Search filter syntax](reference/search_filters.md) — filter fields and + operators per element type, and `--filter-json` shape. diff --git a/skills/api-discovery/reference/search_filters.md b/skills/api-discovery/reference/search_filters.md new file mode 100644 index 0000000..c3443cf --- /dev/null +++ b/skills/api-discovery/reference/search_filters.md @@ -0,0 +1,84 @@ +# `postman search` filter syntax + +Captured from `postman search -h` on the installed CLI. Re-run `-h` +to check for drift before trusting this on anything version-sensitive. + +## Global options (every `search `) + +- `--ownership ` — `organization` (or `org`, default), `external`, + `all`. +- `-n, --limit ` — max results per page, up to 25 (default 10). +- `--cursor ` — from a previous response, to paginate. +- `-o, --output ` — `default` (card list with a web link per + result) or `json` (full detailed response). +- `--filter ` — inline filter string. +- `--filter-json ` — filter as raw JSON; takes precedence over + `--filter` if both are given. + +## `--filter` expression syntax + +- `=` / `!=` for a single value: `workspaceId=ws-1` +- `IN` / `NIN` for comma-separated values: `workspaceId IN ws-1,ws-2` +- Combine multiple conditions with `AND` (case-insensitive operators). +- Quote a value containing spaces or commas: `name="value with spaces"` + +## `--filter-json` shape + +Only a top-level `$and` array of condition objects — no `$or`, no nested +groups: + +```json +{"$and":[{"workspaceId":{"$eq":"ws-abc123"}}]} +``` + +Each condition maps one field to one operator object: `$eq`, `$ne`, `$in`, +`$nin`. + +## Fields shared across all element types + +| Field | Operators | Value | +| --- | --- | --- | +| `privateNetwork` | `$eq`, `$ne` | boolean | +| `publisherIsVerified` | `$eq`, `$ne` | boolean | +| `visibility` | `$eq`, `$ne` | `internal` \| `public` \| `partner` | +| `workspaceId` | `$eq`, `$ne`, `$in`, `$nin` | id | +| `createdBy` | `$eq`, `$ne`, `$in`, `$nin` | user id | +| `organizationId` | `$eq`, `$ne`, `$in`, `$nin` | org id | +| `teamId` | `$eq`, `$ne`, `$in`, `$nin` | team id | +| `isGitConnected` | `$eq`, `$ne` | boolean | + +ID filters expect actual IDs — run a broader search with `--output json` +first to find them. + +## Element-specific fields + +**`requests`** + +| Field | Operators | Value | +| --- | --- | --- | +| `collectionId` | `$eq`, `$ne`, `$in`, `$nin` | id | +| `requestId` | `$eq`, `$ne`, `$in`, `$nin` | id | +| `method` | `$eq`, `$ne`, `$in`, `$nin` | `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, ... | +| `type` | `$eq`, `$ne`, `$in`, `$nin` | `http-request`, `graphql-request`, `grpc-request`, `ws-raw-request`, `ws-socketio-request`, `mqtt-request`, `llm-request` | + +**`specs`** + +| Field | Operators | Value | +| --- | --- | --- | +| `specificationId` | `$eq`, `$ne`, `$in`, `$nin` | id | + +Run `postman search --help` for the exhaustive per-type list — this +file covers `requests` and `specs`; the others (`collections`, +`workspaces`, `flows`, `mocks`, `environments`, `documents`) share the +common fields above plus their own, not yet captured here. + +## Examples + +```bash +postman search requests "login" +postman search requests "auth" --filter "method=POST AND collectionId=collection-uid-1" +postman search requests "upload" --filter "method IN POST,PUT AND workspaceId=ws-abc123" +postman search requests "payment" --ownership external --limit 5 --filter "visibility=public" +postman search specs "billing" --ownership external +postman search specs "payments" --filter "publisherIsVerified=true AND visibility=public" +``` diff --git a/skills/api-mocking/SKILL.md b/skills/api-mocking/SKILL.md new file mode 100644 index 0000000..d29870c --- /dev/null +++ b/skills/api-mocking/SKILL.md @@ -0,0 +1,119 @@ +--- +name: api-mocking +description: Stands up a fake backend that behaves like a real API — from a collection or an OpenAPI spec, running locally or pushed to Postman's cloud for a durable URL — plus request-time scenario and status-code overrides for testing failure paths. Use when the user asks to "mock this API," "create a mock server," "fake the backend," "run tests without hitting the real API," or "simulate an error/out-of-stock response." Covers `postman mock`. Depends on bootstrap for the workspace id only once a mock is pushed to the cloud (`-w`, or the workspace linked in `.postman/resources.yaml`) — generating and running a mock locally needs nothing from bootstrap. +--- + +# API Mocking + +## Overview + +A mock is two files on disk: `config.yaml` (name, port, list of scenarios) +and `default.js` — a plain Node HTTP server, and the mock itself, not a +wrapper around one. Because it's just code, generating, inspecting, running, +and calling a mock are all local and work for a logged-out guest. Only +sharing it — pushing it to the cloud and deploying a durable URL — needs +`postman login`. + +Local and cloud aren't a choice made once at `generate` time. Every mock +starts as a local folder; `mock push` promotes any existing local folder to +the cloud later, whether or not `-w` was passed at generate. Reach for cloud +only when something other than you needs to hit this mock over the network — +a teammate, a CI job elsewhere, a webhook sender. A purely local mock +answering a `postman request` on your machine never needs it. + +## Process + +1. **Generate.** `postman mock generate -n NAME --port N` with no source + scaffolds a complete sample cart mock — the fastest way to a server that + already answers, useful whenever the point is exercising mock *behavior* + rather than a specific API's shape. Pass a real source — + `postman mock generate SOURCE -n NAME --port N`, where `SOURCE` is a + collection folder or an `openapi.yaml` — when the endpoints need to mirror + an actual API. Either form writes `config.yaml` + `default.js` into + `postman/mocks/NAME/`. Adding `-w ` also creates the mock in + that workspace on top of writing the local files — it doesn't replace the + local write, and it requires being logged in. +2. **Run it.** `postman mock run ./postman/mocks/NAME` starts + `Mock server started at http://localhost:PORT`. If the port in + `config.yaml` is taken and `--port` wasn't passed explicitly, it falls + back to a free OS-assigned port instead of erroring — read the real port + off that line rather than assuming the configured one. Naming `--port` + explicitly makes a taken port a hard `Port already in use` error instead. +3. **Call it.** Plain `postman request localhost:PORT/route` returns the + default scenario's response. Two headers change that per-request, with no + restart needed: `x-mock-scenario: ` selects a different scenario + (the valid names live in `config.yaml` — `mock get` only ever shows the + default one), and `x-mock-response-code: ` returns that status + instead. A wrong route and a wrong scenario name both come back as + `Endpoint not defined` — indistinguishable from the message alone. + There's no hot reload: a `default.js` edit does nothing until you + Ctrl+C the running server and `mock run` it again. +4. **Push it, if it needs to leave your machine.** + `postman mock push ./postman/mocks/NAME` is safe to re-run — `Created` + the first time, `Updated` after. It returns a cloud ID that is a *new* + identifier, not the `id` already sitting in `config.yaml` — see + [The three identifiers](#the-three-identifiers) below. It also modifies + `.postman/resources.yaml`; commit that change. +5. **Deploy it, for a URL that outlives your terminal.** + `postman mock deploy CLOUD_ID -s SLUG -y --auto-deploy` prints + `https://SLUG.mock..postman.dev`. Deployed private by + default — callers need an API key — add `--public` only when the mock + should be reachable by anyone with the URL. `-y` alone accepts + private/auto-deploy-off; without `--auto-deploy`, a later `push` doesn't + change what's actually being served until you `deploy` again. +6. **See who's calling it.** `postman mock get CLOUD_ID --json` returns + `.mockServerId`; feed that into `postman mock log MOCK_SERVER_ID --json` + for call entries. An empty log means the URL genuinely hasn't been hit — + a rejected caller still shows up, recorded with its failing status code. +7. **Tear down.** `postman mock delete ./path --yes` (local) or + `postman mock delete CLOUD_ID --yes` (cloud) — both refuse while the + thing is still alive, so stop the local run or bring the deployment down + first. Cloud delete doesn't touch `.postman/resources.yaml`; drop that + line by hand afterward or the repo keeps claiming a mock that's gone. + +To point real request/assertion runs at a mock instead of hand-editing +base-URL variables, see the `api-testing` skill's `--use-mock`/`--mock` +flags on `collection run`. + +## The three identifiers + +`config.yaml`'s local `id`, the cloud ID `push` returns, and the +`mockServerId` from `get CLOUD_ID --json` are three different values, in the +order they become available. Only the second and third are lookups — +`push` is a creation, not a promotion, so passing the `config.yaml` id to any +cloud command is passing the wrong key, not a stale one. + +## Critical Rules + +1. **Every gated cloud command fails the same way:** + `Authentication required. Run postman login or provide --api-key`, + exit 1, nothing half-done. Whether a command is gated is decided by what + you pass it, not the verb — `mock get`/`mock run` take either a local + path (ungated) or a cloud ID (gated); `mock list` is gated only when + called with no path. +2. **`push` is what moves an existing local mock to the cloud — `-w` at + `generate` time is optional, not a fork you must choose up front.** A + mock built as a guest can be pushed and deployed later with no rework. +3. **`--public` on `deploy` is the one action here with real exposure** — it + stands up a server anyone with the URL can hit, with no API key. The + default (private) is the safe one; confirm intent before adding it. +4. **Don't reuse the `config.yaml` id for a cloud command, and don't invent + a `mock generate` flag for regenerating in place.** The reference for + this CLI documents editing `default.js` and restarting as the way to + change a running mock's behavior — no in-place "update from source" verb + is documented. Run `postman mock generate -h` before assuming one exists + rather than guessing a flag name. +5. **`-w`/`--workspace` only exists on `generate`, `list`, `push`, and + `deploy`.** `get`, `run`, `log`, and `delete` already take a path or an + id that says where the mock is — there's nothing left for `-w` to + resolve on those. + +## Verification + +A mock isn't done because `generate` or `run` exited 0 — hit it with +`postman request` and check the actual status/body, or `mock get CLOUD_ID +--json` for a cloud one, then state whether it ended up local or cloud, and +(if deployed) private or public. For a scenario/status-code check, confirm +the header actually changed the response — a typo'd scenario name returns the same +`Endpoint not defined` as a wrong route, so a passing exit code alone proves +nothing. diff --git a/skills/api-monitoring/SKILL.md b/skills/api-monitoring/SKILL.md new file mode 100644 index 0000000..c52d82c --- /dev/null +++ b/skills/api-monitoring/SKILL.md @@ -0,0 +1,136 @@ +--- +name: api-monitoring +description: Creates, schedules, and manages Postman Monitors — recurring checks against a live API — triggers ad hoc runs, inspects job/run history to diagnose failures, and hosts self-hosted execution runners for monitors on a private network. Use when the user asks to "set up a monitor," "run this monitor now," "check monitor results," "pause/resume a monitor," or "set up a runner for our internal APIs." Covers `postman monitor` (create, update, delete, list, get, pause, resume, run, jobs, runs) and `postman runner` (start, list, regions). +--- + +# API Monitoring + +## Overview + +A Monitor is a recurring, scheduled check against a live API. The CLI now +owns its full lifecycle: `monitor create`/`update`/`delete`/`pause`/`resume` +manage the schedule and configuration, `monitor list`/`get` discover and +inspect existing ones, `monitor run` triggers an ad hoc run, and `monitor +jobs`/`monitor runs` inspect what actually happened during a run. There is +no remaining task here that has to go through the Postman app. + +`postman runner` is a separate, infrastructure-level concern: it starts a +self-hosted execution agent so Monitor runs can reach APIs that live behind +a private network Postman's cloud can't reach directly, and it lists the +values (Postman regions or self-hosted runner ids) that `monitor +create`/`update --runner` accepts. + +## Creating and scheduling a monitor + +`monitor create -c ` is the minimum — name defaults to the +linked collection's own name. Workspace comes from `-w`, or falls back to +the workspace named in the local `.postman/resources.yaml` manifest; +without either, creation fails. `--schedule ` plus `--timezone` +(defaults to the host machine's zone) set when it fires; `--runner` +(repeatable) says where from — a Postman region name (`postman runner +regions`) or a self-hosted runner's id (`postman runner list`), and both +can be mixed in the same monitor. `--notify-email` (repeatable) and +`--notification-limit` control failure alerts. The run itself is shaped by +the same options as a collection run — `--retry` (service caps at 2), +`--timeout`, `--delay`, `--strict-ssl`/`--insecure`, +`--follow-redirects`/`--block-redirects`, and dataset iteration via +`--dataset-id`/`--dataset-view-id`/`--iteration-count`/ +`--iteration-strategy`. Creation triggers an immediate run by default; pass +`--no-run-now` to skip that. + +## Updating, pausing, and deleting + +`monitor update ` takes the same schedule/runner/notification/ +run-option flags as `create`, plus `--clear-notifications` to wipe every +recipient. It cannot change the linked collection or environment — delete +and recreate the monitor instead — and it does not pause or resume; use +`monitor pause`/`monitor resume` for that. `monitor delete ` +prompts for confirmation unless `-y`/`--yes` is passed, and is permanent. + +## Discovering and inspecting monitors + +`monitor list` filters by `-w`/`-c`/`--environment`/`--owner`/`--team`/ +`--active`. `--runner ` filters to a *self-hosted* runner id (not a +Postman region) and can't be combined with the other filters. Page with +`--limit`/`--cursor`; `--offset` is accepted by the service but silently +ignored, so the CLI rejects it locally rather than returning a page that +looks right but isn't — use `--cursor` from the previous page's response. +`--columns` picks which fields show, `-f`/`--filter` matches on name within +the page already returned (not a server-side search), and `--sort name|active` +orders it. `monitor get ` shows one monitor's full configuration. + +## Triggering a run + +`monitor run ` runs an existing Monitor synchronously and prints +the result — useful in CI to get a pass/fail right after a deploy rather +than waiting for the next scheduled tick. `-t/--timeout` (default 15 +minutes) caps how long the CLI waits for completion; a timeout hit here is +the CLI giving up on waiting, not the Monitor itself failing. `--async` +submits the run and returns immediately with its job id and Postman URL +instead of waiting at all — reach for this over a long `-t` when the caller +doesn't need the verdict inline. `--json` prints only the verdict as JSON, +for scripting. `-x/--suppress-exit-code` overrides the default +fail-on-failed-run exit code, for a caller that wants to see failures +without breaking a pipeline step. + +## Diagnosing a run + +`monitor jobs list ` lists a monitor's recent jobs; `monitor jobs +get ` reports one job's terminal state and its per-region run +outcomes — a monitor with runners in multiple regions runs once per region +per job. `monitor runs get ` goes one level deeper: which test +assertions ran during one attempt, which failed, and why. Reach for these +instead of re-running blind after a `-t` timeout, or whenever the task is +explaining *why* a monitor failed rather than just that it did. + +## Self-hosted runners + +`runner start --id --key ` (from the Postman app) registers a +runner that executes monitor runs from your own infrastructure instead of +Postman's cloud. This matters only when the monitored API isn't reachable +from the public internet — a public API needs no self-hosted runner. Extra +flags cover the runner's own networking: `--region eu` for EU residency, +`--proxy`/`--egress-proxy`/`--egress-proxy-authz-url` for outbound routing, +`--ssl-extra-ca-certs` for a private CA, and `--metrics`/`--metrics-port` +for a health-check endpoint. Analytics are sent by default; `--no-report-events` +opts out. `runner list` shows the team's registered self-hosted runners — +feed an id from here into `monitor create/update --runner` or `monitor list +--runner`. `runner regions` lists the Postman-region and private-runner +values valid for `--runner` on `monitor create`/`update`, including a +static IP where one is configured — check here before guessing a region +string. + +## Critical Rules + +1. **Monitor creation and scheduling are real CLI tasks now.** Don't send + the user to the Postman app for this — `monitor create` with `-c` and + `--schedule` does it. Notifications here are email only + (`--notify-email`); a request for a different alert channel (Slack, a + webhook) is the one piece still worth checking against the app rather + than assuming a flag exists. +2. **`update` can't move a monitor to a different collection or environment, + and doesn't pause/resume it.** Delete and recreate for the former; use + `pause`/`resume` for the latter. +3. **A `monitor run -t` timeout is a wait cap, not a monitor failure.** + Don't report "the monitor failed" from a timeout without checking + `monitor jobs get`/`monitor runs get` (or the Postman app) for what the + run actually did after the CLI gave up waiting — or avoid the wait + entirely with `--async`. +4. **`--runner` on `monitor create`/`update` takes a region name or a + self-hosted runner id — check `runner regions`/`runner list` before + guessing a string,** and don't suggest `runner start` unless the target + API genuinely isn't reachable from Postman's cloud. +5. **`monitor list --offset` doesn't work — use `--cursor`,** and + `--runner` there can't be combined with the other filters. +6. **`monitor delete` is permanent.** Confirm intent before passing `-y` to + skip its prompt. + +## Verification + +State the monitor/job/run id and the actual pass/fail result or +configuration change, not just that the command exited. For `run`, state +whether it completed synchronously or was submitted `--async` (a job id is +not yet a verdict — resolve it with `monitor jobs get` before reporting a +result). If a self-hosted runner was started, confirm it registered (the +Postman app, or `runner list`, shows it as connected) before assuming +monitor runs will route through it. diff --git a/skills/api-testing/SKILL.md b/skills/api-testing/SKILL.md new file mode 100644 index 0000000..42c0796 --- /dev/null +++ b/skills/api-testing/SKILL.md @@ -0,0 +1,84 @@ +--- +name: api-testing +description: Runs tests against an API from the command line — a single ad-hoc request, a full collection of pm.test assertions, or matching real captured app traffic against a collection contract. Use when the user asks to "test this endpoint," "run this collection," "check the API still works," or "verify my app's requests match the contract." Covers `postman request`, `postman collection run`, and `postman application test`. Depends on bootstrap when the target is a cloud collection or workspace-bound environment; a bare URL or local collection needs nothing from bootstrap. +--- + +# API Testing + +## Overview + +Three tools, matched to what already exists: + +| Have | Use | +| --- | --- | +| Just a URL to check | `postman request` | +| A collection with `pm.test` assertions saved in it | `postman collection run` | +| A real app (browser flow, CLI, service) whose traffic should match a collection's contract | `postman application test` | + +Don't reach for the heavier tool when the lighter one already answers the +question — a one-off endpoint check doesn't need a collection, and a +collection run doesn't need Playwright. + +## `postman request` — over curl, not instead of testing + +A single request with Postman's resolution built in: `-e` resolves +`{{variables}}` from an environment file the same way a collection run +would, `--auth-*` flags cover basic/bearer/digest/oauth/aws/etc. without +hand-building headers, and `--retry`/`--timeout` handle flaky endpoints. +`--script-post-request` can run `pm.test(...)` assertions inline — the exit +code counts *failed assertions*, not just HTTP status, so a 200 with a +failing test still exits nonzero. Useful for a quick check or a CI health +check; not the place to accumulate assertions that should outlive one +command — those belong saved in a collection. + +## `collection run` — the assertion suite + +Debugging a request's behavior during a run (why a `pm.test` failed, what a +request actually sends) means reading the request's own YAML — see the +`collection-schema-v3` skill for that file format before assuming a field's +shape. + +Runs every request in a collection (or a subset via `-i`, repeatable), +executing whatever `pm.test` scripts are already saved in it. +`-d`/`--iteration-data` (or the beta `--iteration-data-dataset` + +`--iteration-data-view` pair) drives data-driven runs across a CSV/JSON +file or a Postman Dataset. `-r junit,html` for CI-consumable reports. +`--use-mock`/`--mock` redirects the run at a mock instead of a real backend +(see the `api-mocking` skill) — reach for this to test request/assertion +logic without depending on a live service. + +## `application test` — contract-matching real traffic + +This doesn't send its own requests. It runs your existing test command +(`--command "npx playwright test"`, or config-driven via +`postman.config.cjs` targets), captures the network traffic that command +generates, and matches/asserts it against your Postman collections — +answering "did my app's actual calls conform to the contract," not "does +this endpoint respond correctly." `--capture-only` skips the matching step +entirely and just exports what was captured as a new v3 collection, +organized by host — a way to bootstrap a collection from real traffic +rather than authoring one from scratch. Results upload to Postman +automatically after each run; `--report-events=false` skips that for a run +that shouldn't be recorded. + +## Critical Rules + +1. **Don't reach for `application test` for something a plain + `collection run` covers.** It exists specifically for matching *captured* + app traffic (via Playwright or similar), not for driving requests itself. +2. **`postman request`'s exit code reflects failed `pm.test` assertions, not + HTTP status alone.** A nonzero exit on a 200 response usually means a + post-request script assertion failed, not a network problem. +3. **Assertions meant to be reused belong in the collection, not on the + command line.** A `--script-post-request` test on `collection run` runs + once and leaves nothing for the next person; save it as a `pm.test` in + the request instead. +4. **`--use-mock` is the way to test without a live backend** — prefer it + over standing up ad hoc fakes or skipping tests that need a dependency. + +## Verification + +State the actual result (pass/fail counts, exit code), not just that the +command ran. For `application test`, state whether it ran in match mode or +`--capture-only` — they answer different questions and shouldn't be +reported the same way. diff --git a/skills/bootstrap/SKILL.md b/skills/bootstrap/SKILL.md new file mode 100644 index 0000000..e22bb4f --- /dev/null +++ b/skills/bootstrap/SKILL.md @@ -0,0 +1,180 @@ +--- +name: bootstrap +description: Resolves the Postman CLI, authenticates, links the workspace, and records this repo's spec path, collections directory and workspace id. Use when the user asks to "set up Postman here", "connect this repo to Postman", "link this workspace", "authenticate with Postman", "postman login", or "run postman init" — and before the api-mocking, api-testing, api-monitoring, flows, performance-testing, api-discovery, or ci-integration skills only when the CLI, the linked workspace or the spec path has not already been confirmed in this session. Those skills stop and point back here if it has not completed; they never re-derive these values themselves. +--- + +# Bootstrap Postman for This Repo + +## Overview + +One-time and idempotent: every other Postman skill in this plugin reads the +values this one records and re-derives none of them. Finding an existing +`postman/` tree or an OpenAPI file is a signal to inspect, not to assume this +repo is already set up. + +## Rules + +- Make HTTP calls with `postman request`, never `curl` or another client — it + reuses saved auth and env vars, syncs to the workspace, and runs test + assertions. +- Never invent a subcommand or a flag. Run `-h` first and believe it. +- Lint specs with `postman spec lint`, never `postman api …` — the API Builder + is deprecated in v12+ and the CLI prints no warning. +- Local commands need no login; only commands reaching the Postman cloud do. + Don't force a login the task doesn't need. +- A missing `postman` binary means install it. Route to `postman-mcp-server` + only after an install has been attempted and actually failed. +- Never fabricate a workspace id, spec path, or collections directory. Report + the gap and stop. +- Never echo an API key or session token into output, logs, or summaries. +- "Present" is not "current": check the version and existing links before + setting anything up. +- Wire up an existing repo only. Never scaffold a new API or a starter spec. +- Write no host-specific paths — one `skills/` directory loads on Claude Code, + Cursor and Kimi Code. + +## Ask the CLI: `-h` + +The CLI is self-describing at different levels. Walk down only as far as the +question needs: + +```bash +postman -h # resources: collection, spec, mock, monitor, workspace, api, flows… +postman -h # that resource's actions +postman -h # real flags, defaults, and worked `Eg.` lines +``` + +Read the third level before writing any command that carries a flag — it is the +only place defaults are stated, and a wrong default fails silently. Live output +is authoritative over any summary, including this file. There is also no single +verb for "is the workspace linked and synced": run `postman workspace -h` and +pick from what it prints. + +--- + +## Process + +Four steps, in order. Stop at the first that fails and report which one. + +## 1. Resolve the CLI + +### 1.1 Check what is already there + +**Present, and at which version?** + +```bash +command -v postman && postman --version +``` + +**Current?** Never blocking — no network is a normal answer. But don't call a +feature missing without having made this comparison. + +```bash +npm view postman-cli version +``` + +### 1.2 Install only if missing + +**Preferred — npm, all platforms:** + +```bash +npm install -g postman-cli +``` + +**Windows, or avoiding a global npm install:** use the platform installers in +[reference/cli_installation.md](reference/cli_installation.md). Every route puts +`postman` on `PATH`. + +**Updating a copy that already exists:** use the same route that installed it. +curl-installed binaries don't take `npm install -g` cleanly. + +**If every route fails:** name what blocked you — no Node, no shell, no write +access, or a hosted session that cannot install — then hand off to the +`postman-mcp-server` skill. An attempted install that actually failed is the +only thing that qualifies. + +## 2. Authenticate, if the task needs it + +### 2.1 Decide whether auth is required + +Local commands need no login, and `postman init` is among them — its own help +says *"No authentication, and safe in CI."* Skip to step 3 unless something in +the task reaches the Postman cloud. + +### 2.2 Sign in + +**With an API key — preferred, non-interactive:** + +```bash +[ -n "$POSTMAN_API_KEY" ] && postman login --with-api-key "$POSTMAN_API_KEY" +``` + +**Browser flow, when that variable is unset:** + +```bash +postman login +``` + +**Never echo the key or token.** Auth state lives in the CLI's own config; this +skill writes no credential file. Report that authentication succeeded, nothing +more. + +## 3. Record the bindings + +### 3.1 Check for an existing record + +Read `.postman/resources.yaml` for `localResources` and `workspace.id`. +Populated → go to step 4. Absent or empty → run init. + +### 3.2 Run init + +`postman init --json` is the agent-facing form. It writes +`.postman/resources.yaml` and scaffolds `postman/` for specs, collections and +environments. Downstream skills read that file and nothing else. + +```bash +postman init --json --no-cloud # local only, no workspace +postman init --json --visibility personal # also create and bind a workspace +``` + +**The workspace step is interactive** without `--no-cloud` or `--visibility`. + +**Read the payload, not stderr.** Take `bindings` and `exitCode` from the JSON. +Each binding reports a `source` of `inferred` or `none` — an inferred spec is a +guess worth confirming before building on it. + +**Exit codes that are not failures:** 2 means several specs could be +authoritative, so re-run with `--spec `. 5 means the local files were +written but the requested workspace was not created — it does *not* mean re-run. + +## 4. Verify and report + +### 4.1 Checkpoints + +- `postman --version` returned a real version. +- Auth is confirmed, or established as not required for this task. +- `.postman/resources.yaml` names a spec or a collections directory. +- `workspace.id` is set, or the run was deliberately local-only — `--no-cloud` + leaves it empty and still exits 0, which is a pass, not a gap. + +"The CLI is installed" is not the bar, and a loaded skill configures nothing. + +### 4.2 Summary format + +```md +## Postman bootstrap +- **CLI**: (latest: | not checked) +- **Auth**: +- **Workspace**: +- **Spec path**: +- **Collections dir**: +``` + +--- + +## Reference Files + +- `collection-schema-v3` skill — read when inspecting or writing the + collection files this skill resolves. +- [CLI Installation](reference/cli_installation.md) — read for install, update + and uninstall commands per platform. diff --git a/skills/bootstrap/reference/cli_installation.md b/skills/bootstrap/reference/cli_installation.md new file mode 100644 index 0000000..c97c3f6 --- /dev/null +++ b/skills/bootstrap/reference/cli_installation.md @@ -0,0 +1,58 @@ +# Postman CLI Installation + +A global install, on `PATH`, installed by one of three tools depending on +platform. Whichever one put the binary there is the one to use again when +updating it — mixing tools leaves two `postman` binaries and a `PATH` +question. + +## Install + +**npm (all platforms):** + +```bash +npm install -g postman-cli +``` + +**macOS, Linux, and WSL (curl):** + +```bash +curl -o- "https://dl-cli.pstmn.io/install/unix.sh" | sh +``` + +**Windows (PowerShell):** + +```powershell +powershell.exe -NoProfile -InputFormat None -ExecutionPolicy AllSigned -Command "[System.Net.ServicePointManager]::SecurityProtocol = 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://dl-cli.pstmn.io/install/win64.ps1'))" +``` + +## Check for drift + +```bash +postman --version # installed +npm view postman-cli version # latest published +``` + +## Update + +Run the same command that installed it — the npm, curl or PowerShell line +above, whichever put the binary there. Using a different one leaves two +`postman` binaries and a `PATH` question. Never `npm install -g` over a copy +that came from the curl installer or a system package manager. + +The CLI has no self-update verb. `postman skills update` is a different +thing: it refreshes a repository's committed `postman/skills/`, not the +binary. + +## Uninstall + +npm installations: + +```bash +npm uninstall -g postman-cli +``` + +Other install methods: delete the `postman` binary from its install +directory (`%USERPROFILE%\AppData\Local\Microsoft\WindowsApps` on Windows, +`/usr/local/bin` on macOS/Linux/WSL). + +Source: https://learning.postman.com/docs/postman-cli/postman-cli-installation/ diff --git a/skills/ci-integration/SKILL.md b/skills/ci-integration/SKILL.md new file mode 100644 index 0000000..38855bb --- /dev/null +++ b/skills/ci-integration/SKILL.md @@ -0,0 +1,121 @@ +--- +name: ci-integration +description: Common CI integrations that can added as independent pass/fail gates. Use when the user asks to "add Postman to CI," "run this collection on every PR," "fail the build on a governance violation," or "push to the postman cloud workspace after merge to main", "add some api related operation in my Github actions". +--- + +# CI Integration + +## Overview +These are some common workflows that one can add in their CI pipeline leveraging postman cli. + +## Run a collection — a gated pipeline step + +`postman collection run ` exits nonzero on a failed `pm.test` +assertion, which is what makes it a usable gate — see `api-testing` for how +that exit code actually gets set. What's CI-specific: `-r junit,html` (or +`--reporter-*-export`) writes a report your CI provider can surface as +build artifacts or test annotations, instead of leaving the result buried in +a log. `--bail` stops the run early on the first failure when a fast signal +matters more than a full report. + +## Lint — pick the target that matches the gate you want + +Three verbs look interchangeable and aren't — only two of them apply your +organization's governance rules, and the CLI's own `-h` output is where that +becomes visible (no assumption below goes further than what it printed): + +| Want to check | Command | Applies org governance? | +| --- | --- | --- | +| One spec against your rules | `spec lint --workspace-id -f error` | Yes, via `--workspace-id` | +| One collection's structure/style | `collection lint -f error` | **No** — this verb takes no `--workspace-id` at all | +| The whole workspace: every entity plus `.postman/resources.yaml` | `workspace lint --workspace-id -f error` | Yes | + +`collection lint` is a schema/style check only — running it and reporting +"governance passed" overstates what it did. If the ask is "does this +collection violate our rules," `workspace lint` is the one that actually +answers it (and covers every collection in the repo in one pass); reach for +bare `collection lint` only when there's no workspace to fetch rules from +yet. + +## Push to workspace — only after merge + +`postman workspace push -y` is the one command in this skill that changes +shared cloud state, so it belongs behind a merge-to-main trigger, not a PR +trigger. `-y` skips confirmation prompts a non-interactive job can't answer. +Leave `--no-prepare` off — the default prepare step is what assigns real IDs +to entities that are new since the last push; skipping it because a run +felt slow trades a few seconds for a push that silently fails to create +anything new. + +`--push-strategy force-sync` mirrors the whole workspace, deleting any cloud +entity with no local counterpart — genuinely destructive, and not the +default for a reason. See Critical Rules before adding it to a merge job. + +## AI readiness threshold + +`collection ai-readiness --min-score ` and its spec-side +counterpart `spec ai-readiness --min-score ` (see `ai-readiness` +skill) are a fourth, separate gate — they score AI-agent consumability, not +test results or governance/structural style. Keep either in its own step: +folding it into the same step as `run` or one of the `lint` verbs above +hides which kind of check actually failed when the job goes red. Pick the +verb that matches what's checked into the repo — `collection ai-readiness` +for a git-synced collection, `spec ai-readiness` for an OpenAPI spec with no +collection generated from it yet. + +```yaml +- run: postman collection ai-readiness ./postman/collections/My\ API --min-score 70 +``` + +## Critical Rules + +1. **Never collapse `run`, `lint`, and `ai-readiness` into one step, and + never pass `-x`/`--suppress-exit-code` to a CI run.** One combined exit + code hides which check broke; a suppressed one hides that anything broke + at all. +2. **Gate `workspace push` to the merge event, never a PR event.** Everything + else in this skill is read-only against the cloud; this is the one + command that writes to it, so a PR-triggered push ships an unmerged + branch's entities to the shared workspace. +3. **`--push-strategy force-sync` deletes cloud entities absent locally.** + Only add it to a job whose explicit job is mirroring the workspace exactly, + with that intent confirmed — never as the default merge step, where the + default (create/update-only) strategy is the safe choice. +4. **Authenticate once, non-interactively:** + `postman login --with-api-key "$POSTMAN_API_KEY"`, reading the key from + the CI provider's secret store. Don't reach for `collection run`'s + `--postman-api-key` as the general answer — it's US-region only — and + `spec lint`/`workspace push` don't take it at all. + + ```yaml + # WRONG — key committed in plain text, and scoped to one command anyway + - run: postman collection run api.json --postman-api-key PMAK-abc123... + + # CORRECT — one non-interactive login, key from the provider's secret store + - run: postman login --with-api-key "$POSTMAN_API_KEY" + - run: postman collection run api.json + - run: postman spec lint spec.yaml --workspace-id $WS -f error + ``` +5. **Never `newman run` in place of `postman collection run`.** The CLI is + the supported runner every other skill here assumes; Newman forks the + toolchain and skips whatever reporting/governance depends on the CLI + specifically. + +## Verification + +State each gate that ran and its individual result — not "CI passed," but +which check ran, what it checked (governance vs. structure per the Lint +table above, or AI-agent consumability for `ai-readiness`), and its exit +code. If `workspace push` ran, confirm it was triggered by the merge event +and not a PR event, state which push strategy was used, and report +`Created`/`Updated` per entity rather than just "push succeeded." Confirm +no secret value appears literally in the committed workflow file. + +## Reference + +- `api-testing` skill — `collection run`'s exit-code semantics and reporter + flags in full. +- `collection-schema-v3` skill — what `workspace push` is actually pushing. +- `bootstrap` skill — CLI resolution, workspace linking, `.postman/resources.yaml`. +- `ai-readiness` skill — `collection ai-readiness`, `spec ai-readiness`, and + their `--min-score` gate. diff --git a/skills/collection-schema-v3/SKILL.md b/skills/collection-schema-v3/SKILL.md new file mode 100644 index 0000000..a9fcbe4 --- /dev/null +++ b/skills/collection-schema-v3/SKILL.md @@ -0,0 +1,208 @@ +--- +name: collection-schema-v3 +description: The reference for the git-native v3 collection file format — one YAML file per request/folder/example under postman/collections/, plus postman/environments/. Read before writing, editing, or generating any file in either directory by hand, or before debugging a `collection lint` failure. Covers the HTTP request/example/definition schema, environment schema, and the YAML/naming rules that make files parse — GraphQL, gRPC, WebSocket, Socket.IO, MQTT, MCP, and LLM request schemas are non-HTTP protocols and live in reference/other_protocols.md, read only when a collection actually uses one. +--- + +# Collection Schema (v3, Git-Native) + +## Overview + +A v3 collection is a directory tree under `postman/collections/`, one file +per entity — every request, every folder's metadata, every saved example is +its own file. There is no single collection.json to open and edit; the +directory structure itself *is* the collection. + +```text +postman/collections/ + bookstore api/ + .resources/ + definition.yaml (optional) + get all books.resources/ + examples/ + 200 OK.example.yaml + 400 Bad Request.example.yaml + 500 Internal Server Error.example.yaml + get all books.request.yaml + get-book-by-id.request.yaml + add new book.request.yaml + authentication/ + .resources/ + definition.yaml (optional) + signup.request.yaml + login.request.yaml +``` + +- Every folder under `postman/collections/` is a collection; it can contain + subfolders and requests. +- A folder or collection can have a `.resources/` directory — an optional + metadata directory for that scope. `.resources/definition.yaml` holds the + collection/folder's own metadata; request examples live under + `.resources/.resources/examples/`. +- Never place a request file inside a `.resources/` directory — those are + metadata-only. + +## Definition file (`.resources/definition.yaml`) + +Optional metadata for a collection or folder: + +- `$kind: "collection"` — required, even for a folder's definition. +- `name` — optional, defaults to the filesystem folder name. +- `description` — optional. +- `variables` — array of `{key, value, description?, disabled?}`. `value` + must be a string; `disabled` a boolean. +- `auth` — a single auth object `{type, credentials: [{key, value}, ...]}`, + or an array for multiAuth: `[{id, name, type, credentials, rules?}, ...]`. +- `scripts` — array of `{type, code, language: "text/javascript"}`. `type` + is one of `http:beforeRequest`, `http:afterResponse`, + `graphql:beforeQuery`, `graphql:afterResponse`, `grpc:beforeInvoke`, + `grpc:onIncomingMessage`, `grpc:afterResponse`. +- `order` — number, used for folder ordering. + +## HTTP request (`*.request.yaml`) + +- `$kind: "http-request"` — required. +- `name` — optional (see naming rules below for when to include it). +- `order` — number; only used for relative comparison, so space values out + (e.g. multiples of 1000) rather than packing them tight — a later + insertion between two requests shouldn't force renumbering every sibling. +- `url` — string, with `{{varName}}` variable syntax. +- `method` — `GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS`. +- `headers` — array of `{key, value, description?, disabled?}`. +- `queryParams` — array of `{key, value, description?, disabled?}`. +- `pathVariables` — array of `{key, value, description?}`. +- `body` — `{type, content}`; `type` required whenever `body` is present. + - Types: `json`, `formdata`, `urlencoded`, `text`, `xml`, `html`, + `javascript`, `file`, `none`. + - `json`/`text`/`xml`/`html`/`javascript`: `content` is a string. + - `formdata`: `content` is an array of + `{key, type: "text"|"file", value or src, contentType?, description?}`. + - `urlencoded`: `content` is an array of `{key, value, description?}`. +- `auth` — `{type, credentials}`. +- `settings` — + `{protocolVersion?, strictSSL?, followRedirects?, maxRedirects?, disabledSystemHeaders?}`. +- `scripts` — array of `{type: "beforeRequest"|"afterResponse", code, language: "text/javascript"}`. +- `examples` — optional, a relative path to the examples directory, e.g. + `./.resources/.resources/examples/`. + +## HTTP example (`*.example.yaml`) + +- `$kind: "http-example"` — required. +- `name` — optional. +- `request: {url, method}`. +- `response: {statusCode, statusText, headers: [{key, value}], body: {type, content}}`. +- `order` — optional. + +Saved examples are what `collection ai-readiness` checks for — a request +with no examples scores worse for agent consumption even if perfectly +valid structurally. + +## Environments (`postman/environments/*.yaml`) + +- `name` — required. +- `values` — array of `{key, value: string, enabled, type}`. `value` must + be a string (same rule as collection variables); `enabled` is boolean; + `type` is a string, e.g. `"default"`. + +## YAML rules + +Invalid YAML breaks parsing silently in confusing ways — when in doubt, +single-quote it: + +1. Single-quote any value containing `{{variables}}`: + `url: '{{base_url}}/users'` — never leave it unquoted. +2. Single-quote values containing `: # & * ! [ ] { } > |`, e.g. + `name: 'Health check: v2'`. +3. Multi-line content (JSON bodies, scripts, queries) uses a `|-` block + scalar: + ```yaml + body: + type: json + content: |- + { + "name": "example" + } + ``` +4. Quote strings that resemble booleans/numbers when a string is intended: + `value: "true"`, `value: "123"`. +5. `order` must be a bare number, never quoted: `order: 1000`. +6. Single-quote file paths and use forward slashes only: + `examples: './.resources/name.resources/examples'`. + +## Naming rules + +- `` (the filename stem before `.request.yaml`) must not + contain `/ \ : * ? " < > |` — sanitize to `-`. +- Include `name` in the file only when it differs from `` + (e.g. `name: 'Health/check'` inside `Health-check.request.yaml`, since the + filename itself can't hold the `/`). +- Filenames must be unique, case-insensitively, per directory. + +## Worked example: "bookstore api" + +`postman/collections/bookstore api/get all books.request.yaml` +```yaml +$kind: http-request +method: GET +url: '{{base_url}}/books' +order: 1000 +``` + +`postman/collections/bookstore api/get-book-by-id.request.yaml` +```yaml +$kind: http-request +name: 'get book by :id' +method: GET +url: '{{base_url}}/books/:id' +order: 2000 +pathVariables: + - key: id + value: '1' +``` + +`postman/collections/bookstore api/add new book.request.yaml` +```yaml +$kind: http-request +method: POST +url: '{{base_url}}/books' +order: 3000 +headers: + - key: Content-Type + value: application/json +body: + type: json + content: |- + { + "title": "Example Book", + "author": "Jane Doe" + } +``` + +`postman/collections/bookstore api/.resources/definition.yaml` +```yaml +$kind: collection +name: Bookstore API +variables: + - key: base_url + value: 'https://api.bookstore.com/v1' +``` + +## Critical Rules + +1. **Every entity is its own file — there's no single collection.json to + open.** A request, its parent folder's metadata, and its saved examples + are three separate files, not sections of one document. +2. **Unquoted `{{variables}}` or special characters are the most common way + a hand-written file fails to parse.** Single-quote per the YAML rules + above rather than debugging a cryptic lint error after the fact. +3. **`order` is relative, not an index.** Don't renumber every sibling file + to insert one request — leave headroom (spacing of 1000) from the start. +4. **This file covers HTTP only.** A collection using GraphQL, gRPC, + WebSocket, Socket.IO, MQTT, MCP, or LLM requests needs + [reference/other_protocols.md](reference/other_protocols.md) — don't + guess those schemas from the HTTP shape above, they diverge in real ways + (e.g. gRPC's `methodDescriptor`, LLM's `userPrompts`/`systemPrompts`). + +## Reference + +- [Other request protocols](reference/other_protocols.md) — GraphQL, gRPC, + WebSocket, Socket.IO, MQTT, MCP, and LLM request schemas. diff --git a/skills/collection-schema-v3/reference/other_protocols.md b/skills/collection-schema-v3/reference/other_protocols.md new file mode 100644 index 0000000..3a21b8b --- /dev/null +++ b/skills/collection-schema-v3/reference/other_protocols.md @@ -0,0 +1,86 @@ +# Non-HTTP request schemas (v3) + +Read this only when a collection actually contains one of these request +types — for the common case, the HTTP schema in the parent +[SKILL.md](../SKILL.md) is the one that applies. + +## GraphQL request + +- `$kind: "graphql-request"` — required. +- `url` — string. +- `order` — optional. +- `query` — string (the GraphQL query). +- `variables` — string (a YAML string containing a JSON object). +- `headers` — array of `{key, value, description?, disabled?}`. +- `auth` — `{type, credentials}`. +- `settings` — `{disabledSystemHeaders?}`. +- `scripts` — array of `{type: "beforeQuery"|"afterResponse", code, language}`. + +## gRPC request + +- `$kind: "grpc-request"` — required. +- `url` — string. +- `order` — optional. +- `methodPath` — string. +- `methodDescriptor` — string. +- `message` — `{content: string (JSON)}`. +- `metadata` — array of `{key, value, description?}`. +- `auth` — `{type, credentials}`. +- `settings` — + `{secureConnection?, strictSSL?, maxResponseMessageSize?, includeDefaultFields?, connectionTimeout?}`. +- `scripts` — array of `{type: "beforeInvoke"|"afterResponse", code, language}`. + +## WebSocket request + +- `$kind: "websocket-request"` — required. +- `url` — string. +- `order` — optional. +- `headers` — array of `{key, value, description?, disabled?}`. +- `queryParams` — array of `{key, value, description?, disabled?}`. +- `settings` — `{handshakeTimeout?, retryCount?, retryDelay?, maxPayload?, strictSSL?}`. + +## Socket.IO request + +- `$kind: "socket.io-request"` — required. +- `url` — string. +- `order` — optional. +- `headers` — array of `{key, value}`. +- `queryParams` — array of `{key, value}`. +- `events` — array of `{name, description?, subscribeOnConnect: boolean}`. +- `settings` — `{version?, path?, handshakeTimeout?, retryCount?, retryDelay?, strictSSL?}`. + +## MQTT request + +- `$kind: "mqtt-request"` — required. +- `url` — string. +- `order` — optional. +- `clientId` — string. +- `version` — `4 | 5`. +- `topics` — array of + `{name, qos: 0|1|2, subscribe: boolean, description?, settings: {noLocal?, retainAsPublished?, retainHandling?, subscriptionIdentifier?}}`. +- `lastWill` — `{topic, payload, qos, retain, type: "text"|"json", properties: {messageExpiryInterval?, contentType?}}`. +- `properties` — + `{sessionExpiryInterval?, receiveMaximum?, maximumPacketSize?, requestResponseInformation?, userProperties: [{key, value}]}`. +- `settings` — `{cleanSession?, keepAlive?, autoReconnect?, connectionTimeout?, strictSSL?}`. + +## MCP request + +- `$kind: "mcp-request"` — required. +- `transport` — `"sse" | "stdio"`. +- `order` — optional. +- SSE shape: `{url, headers?, message, auth?, settings: {strictSSL?, requestTimeout?, sessionTimeout?}}`. +- STDIO shape: `{command, env: [{key, value}], message, auth?, settings: {requestTimeout?}}`. + +## LLM request + +- `$kind: "llm-request"` — required. +- `url` — string. +- `order` — optional. +- `config` — `{model, provider}`. +- `userPrompts` — array of `{id, value, timestamp, active, type: "text"}`. +- `systemPrompts` — array of `{id, value, timestamp, active, type: "text"}`. +- `mcpConfig` — optional string (JSON config). +- `enabledTools` — optional array of strings. +- `auth` — `{type, credentials}`. +- `settings` — + `{temperature?, maxToken?, streamResponse?, responseFormatJSON?, topP?, presencePenalty?, frequencyPenalty?, maxSteps?, streamTools?}`. diff --git a/skills/deploy-flow/SKILL.md b/skills/deploy-flow/SKILL.md deleted file mode 100644 index 0345e2e..0000000 --- a/skills/deploy-flow/SKILL.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -name: deploy-flow -description: Deploy a Postman Flow so it becomes triggerable, using the Postman CLI. Use when the user wants to deploy, publish, or make a flow callable, or when trigger-flow found an undeployed flow and the user confirmed. ---- - -You are a Postman Flows assistant that deploys Flows using the Postman CLI. Deploying makes a flow triggerable and returns its **Trigger URL**. - -## The command this wraps - -```bash -POSTMAN_CLI_SOURCE=claude-code-plugin postman flows deploy --path [options] -``` - -Options: -- `-p, --path ` — **required** URL path for the trigger (e.g. `/checkout`) -- `-t, --timeout ` — HTTP session timeout, 5000ms–60000ms (default `10000ms`) -- `-a, --auth` — enable authentication on the trigger - -## Step 1: Resolve the flow ID - -If given a name rather than a 24-char ID, resolve it with the `list-flows` skill (ask which workspace if unknown; disambiguate on multiple matches). - -## Step 2: Propose a trigger path and CONFIRM - -Deploy **requires** a URL path. Propose a sensible default derived from the flow name: -- "Checkout" → `/checkout` -- "Nightly Report" → `/nightly-report` - -Confirm the path and the deploy action with the user before running — deploy is mutating and requires explicit confirmation. - -Ask about authentication only if relevant ("Should the trigger require auth?"). Add `--auth` only if they say yes. - -## Step 3: Deploy - -Show the exact command, then run it after confirmation: - -```bash -POSTMAN_CLI_SOURCE=claude-code-plugin postman flows deploy 12345-67890-abcdef --path /checkout -``` - -Report back: -- the resulting **Trigger URL** -- whether the **trigger is enabled**. If the CLI notes the trigger is off, tell the user and offer to enable it: - ```bash - POSTMAN_CLI_SOURCE=claude-code-plugin postman flows update 12345-67890-abcdef --trigger on - ``` - (enabling is also a state change → confirm first). - -Example report: -``` -Deployed the Checkout flow. - Trigger URL: https:///checkout - Trigger: enabled -``` - -## Step 4: Hand back to trigger (if part of deploy-then-trigger) - -If deploying was requested so the user could run the flow, hand control back to the `trigger-flow` skill to fire it and report the Run ID + status + response — completing the deploy-then-trigger journey in one conversation. - ---- - -Read `references/flows-cli-baseline.md` for CLI prefixing, credential reuse, and error handling rules. - -Deploying and enabling a trigger are mutating actions — confirm with the user before running. On a path conflict, surface the CLI message and propose an alternative path. diff --git a/skills/deploy-flow/references/flows-cli-baseline.md b/skills/deploy-flow/references/flows-cli-baseline.md deleted file mode 100644 index d4d3f3c..0000000 --- a/skills/deploy-flow/references/flows-cli-baseline.md +++ /dev/null @@ -1,9 +0,0 @@ -# Flows CLI Baseline - -These rules apply to every Flows CLI skill. - -- Prefix every CLI call with `POSTMAN_CLI_SOURCE=claude-code-plugin` for telemetry attribution. -- Reuse existing `postman login` / API key credentials. Do not trigger a second authentication. -- Surface CLI errors verbatim. Do not assert access the CLI does not grant. -- **CLI not installed:** "Postman CLI is not installed. Install with: `npm install -g postman-cli`" -- **Not authenticated:** "Run `postman login` (or set `POSTMAN_API_KEY`)." diff --git a/skills/flows/SKILL.md b/skills/flows/SKILL.md new file mode 100644 index 0000000..0a7d65e --- /dev/null +++ b/skills/flows/SKILL.md @@ -0,0 +1,212 @@ +--- +name: flows +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`. +--- + +# Postman Flows + +## Overview + +Listing flows, running them, deploying them so they become callable, and +tracing a failed run to the block that caused it — all through +`postman flows`. + +## Core knowledge + +A flow is a graph of blocks, not a script. That single fact drives the rest of +this skill: a flow has two independent execution paths, and its HTTP response +describes one block rather than the whole graph, so debugging takes a +different command than running. + +### Local file vs deployed artifact + +`run` and `trigger` are not two ways to execute one flow. Postman Flows has +two Native Git modes, and they are isolated from each other: + +- **Cloud View** (the default) syncs flows to Postman Cloud, which is what + makes them shareable and **deployable** — so Cloud View is the only side + `deploy`, `trigger`, `update`, `list-runs` and `get-run` ever address. +- **Local View** stores flows as JSON in a local Git repo, updated as they are + edited. Those flows **cannot be shared or deployed**, have no snapshots, and + are isolated from the flows in Cloud View. + +| | `flows run ` | `flows trigger ` | +| --- | --- | --- | +| Executes | a flow JSON file on this machine | the cloud-deployed flow, via its webhook | +| Returns | status, output, test results, exit code | Run ID + HTTP status + response body | +| Observability | own stdout, `--output`, `--reporters` | `get-run`, per block | +| Environment file | `-e/--environment` | not supported | + +`run` exits nonzero on failure, which is what lets a CI job gate on it. +`trigger` goes through the real webhook URL, so it exercises the deployed path +end-to-end — auth and trigger configuration included — and registers a cloud +run that `get-run` can explain block by block. + +`postman init` scaffolds `postman/flows/`, and Postman's `flows run` examples +use that path. Note what puts files there: the Git-connected Flows experience +is **desktop-app only**, so `postman/flows/*.json` is written by the desktop +app's Local View, not by the CLI — `workspace push`/`pull` carry no flows +handling whatever else they sync. Don't tell a user to `workspace pull` to +obtain a flow file. + +### What deploying buys, and what it requires + +Deploying puts the flow in Postman's cloud and attaches an HTTP trigger, which +is what makes it reachable by schedules, webhooks, third-party apps, and other +APIs — the flow stops being something a human opens and becomes callable +infrastructure. + +Three preconditions sit outside the CLI, so no flag or retry satisfies them: +the flow must be in Cloud View, its Start block must be configured with an API +request trigger, and its canvas must have a Response block. Check these before +re-running a failed deploy with different arguments. + +`--path` is a suffix appended to a generated base URL, not a full URL. + +### Inputs: `-i` versus a scenario + +A scenario is a named input set stored **in the flow definition**, generated +when someone adds an input to the Start block. Because it travels with the +flow, `-s "Staging"` is reproducible across invocations and across people, +where `-i key=value` is per-invocation. Start-block inputs can be declared +secret, which is what `--show-secrets` unmasks in dry-run output. + +Precedence: `-s` supplies payload, headers, and query; `--headers` and +`--query` override it; `-i`/`-f` override its values. + +### Identifiers + +`flows list` is the only way to turn a flow name into an id — +`.postman/resources.yaml` maps collections to cloud ids but has no flows +section, so there is nothing local to read. Both `list` and `list-runs` +**require** `-w/--workspace`; take that id from `workspace.id` in +`.postman/resources.yaml`, which `bootstrap` records. + +Run IDs have no single documented shape (`session-abc123` and `main/1a123ab1` +both appear in Postman's own material). Use whatever `trigger` or `list-runs` +printed, verbatim, and apply the same rule to flow ids. + +### Plan and permission gating + +`flows run` is documented as Enterprise-only, and the cloud subcommands need +`postman login`. `Access denied. Please check your permissions for the +specified resource.` on *every* workspace is a credential-scope or plan +signal, not a wrong-workspace signal — and never means the workspace has no +flows. + +## Deploying: propose, confirm, then verify + +Deploy is the one multi-phase workflow here, because it is mutating and +because its result is only half-useful without the follow-up check. + +1. **Resolve the id.** `flows list --workspace --filter "Checkout"`. On + multiple matches, show name + id + last-updated and let the user pick. +2. **Propose the path.** Derive it from the flow name — "Checkout" → + `/checkout` — so the user is confirming a concrete value rather than + answering an open question. Raise `--auth` here if the trigger will be + reachable by anyone who learns the URL. +3. **Confirm, then run** `flows deploy --path /checkout`. +4. **Report the Trigger URL and whether the trigger is enabled.** A deploy can + land with the trigger off, which looks identical to a broken deploy at call + time. If it is off, offer `flows update --trigger on`. + +When the deploy existed only so the flow could be run, trigger it in the same +turn and report the Run ID — deploy-then-trigger is one job. + +## Running and triggering + +Show the command before running it, and map the request onto flags: inputs to +`-i`, a payload file to `-f`, query to `-q`, headers to `--headers`, a named +scenario to `-s`. + +```bash +postman flows run postman/flows/checkout.json -i amount=4200 +postman flows trigger -i amount=4200 +``` + +`run` is documented as Enterprise-only, so check the plan before building a +workflow on the local path. Where the flow is already in Cloud View, `trigger` +covers the gap; a Local View flow has no such fallback, since it cannot be +deployed. + +`-n/--dry-run` on `trigger` prints the resolved URL and payload without +sending — worth reaching for when a flow writes to real systems, since a +trigger is not a read-only probe. For CI, `--output json` and `--reporters +html` persist results, and `--workspace` is required if the flow contains +connector blocks (it fails at the block, not at startup). + +Report the Run ID on every trigger, including successes; it is the only handle +on the run afterwards. + +Two failures are recoverable rather than terminal, and both recover through a +confirmed mutation. A 404 hinting `To deploy it, run: postman flows deploy` +means the flow exists but was never deployed — offer the deploy above, then +re-trigger. A disabled-trigger error means it is deployed but not accepting +calls — offer `flows update --trigger on`, then trigger. + +## Debugging a run + +A trigger's response body is the Response block's output. A flow can answer +200 with a failed block upstream, and a 500 says nothing about which block +produced it — so read the run, not the response. + +```bash +postman flows list-runs --workspace --flow --range 3d +postman flows get-run --run-id --logs +``` + +`list-runs` recovers a Run ID nobody wrote down; its `--range` defaults to +`1h`, so widen it before concluding a run is missing. Start `get-run` without +`--logs` and add them when the summary does not explain the failure; +`--filter` narrows to a block-id prefix. + +Report the failing block, the reason, and the run status: + +``` +Run session-abc123 — failed + Failing block: "HTTP Request (Get Orders)" + Reason: downstream returned 504 after 10s timeout + Status: error +``` + +## Critical Rules + +1. **Resolve ids, never infer them.** A name is not an id, and no id format is + documented well enough to validate against. Ambiguous name → present + candidates and ask. +2. **`deploy` and `update` need explicit confirmation.** They change what the + flow does for every caller: a deploy exposes a trigger path, `--trigger + on|off` starts or stops accepting calls, and `--auth off` removes + authentication from a live trigger. +3. **Report the failing block, not the log.** `--logs` output is input to your + analysis; the user needs the block, the reason, and the status. +4. **Surface CLI errors verbatim** and read them literally. "Flow file not + found", a required-option error, and "Access denied" have three different + fixes, and only the last is about permissions. +5. **A missing or unauthenticated CLI is `bootstrap`'s job** — route there + rather than improvising an install or a second login. + +## Anti-patterns + +1. **Don't substitute `run` for `trigger` when a flow isn't deployed.** A + green local run says nothing about the deployed path a caller hits, and a + Local View flow cannot be deployed at all. +2. **Don't hunt for a different workspace id when access is denied across + every workspace you try.** A blanket denial points at the credential's + scope or the plan, not at the id. +3. **Don't pass `-x/--suppress-exit-code` in CI.** It makes a failed flow + report success to the pipeline, which removes the only thing gating it. +4. **Don't put reusable inputs on the command line.** A payload that matters + more than once belongs in a Start-block scenario, where it travels with the + flow. + +## Reference + +- [Flows CLI flags](reference/flow_cli_flags.md) — full flag tables per + subcommand, the BETA dataset-iteration flags, and the short-flag collisions + between subcommands. Read before composing a command with flags not shown + above. +- `bootstrap` skill — CLI install, login, and the workspace id these commands + require. +- `api-discovery` skill — `postman search flows` finds a flow by text across + Postman, a different dataset from `flows list`'s workspace enumeration. diff --git a/skills/flows/reference/flow_cli_flags.md b/skills/flows/reference/flow_cli_flags.md new file mode 100644 index 0000000..3175da7 --- /dev/null +++ b/skills/flows/reference/flow_cli_flags.md @@ -0,0 +1,111 @@ +# Flows CLI Flags + +Captured from `postman flows -h` and verified on CLI +**1.58.0**. Live `-h` output is authoritative over this file — re-run it if +the installed CLI is newer, since `flows` is an actively changing surface. + +Every subcommand below also accepts `--verbose`, `--debug`, and `--json`. + +**Short flags are not stable across subcommands.** `-f` is `--filter` on +`list`, `--input-file` on `trigger` and `run`, and `--flow` on `list-runs`; +`-r` is `--result` on `trigger`, `--range` on `list-runs`, and `--run-id` on +`get-run`; `-t` is `--timeout` on `deploy` but `--trigger` on `update`. Read +the table for the subcommand you are actually invoking, and prefer the long +form when composing a command from more than one table. + +## `flows list` + +| Flag | Notes | +| --- | --- | +| `-w, --workspace ` | **Required** — the CLI exits 1 with `required option '-w, --workspace ' not specified`. | +| `-f, --filter ` | Name prefix **or** regex, e.g. `--filter "^Test.*"`. | +| `-s, --sort ` | `name` or `updated`. Default `updated`. | +| `-p, --paginate` | Page through all flows. | + +## `flows trigger ` + +| Flag | Notes | +| --- | --- | +| `-i, --input ` | Repeatable. Trigger payload values. | +| `-f, --input-file ` | Repeatable. Payload from JSON files. Combines with `-i`, which overrides. | +| `-q, --query ` | Repeatable. Query parameters. | +| `--headers ` | Repeatable. Custom headers. | +| `-s, --scenario ` | Named scenario from the flow definition; builds payload, headers and query. **`--headers` and `--query` override it.** | +| `-n, --dry-run` | Print request URL + payload, send nothing. | +| `--show-secrets` | Unmask auth tokens in dry-run output. Masked by default. | +| `-r, --result` | Print only the response body. | + +## `flows deploy ` + +| Flag | Notes | +| --- | --- | +| `-p, --path ` | **Required** — `-h` carries no `(required)` annotation, but omitting it exits 1. A suffix appended to a generated base URL, e.g. `/my-trigger`. | +| `-t, --timeout ` | HTTP session timeout, **5000ms–60000ms**, default `"10000ms"`. Value carries units — `5000ms`, not `5000`. | +| `-a, --auth` | Boolean switch. Enables auth on the trigger. Default off. | + +Note the asymmetry with `update`: here `--auth` is a bare flag; on `update` it +takes `on|off`. + +## `flows update ` + +| Flag | Notes | +| --- | --- | +| `-t, --trigger ` | Enable/disable the trigger. Takes an explicit value. | +| `-a, --auth ` | Enable/disable authentication on the trigger. Takes an explicit value. | + +**At least one of the two is required**: a bare `flows update ` exits 1 +with `Invalid command parameters: trigger: At least one option is required: +--trigger or --auth`. + +Both are mutating and confirmation-gated. `--auth off` strips authentication +from a live trigger — never run it as a convenience. + +## `flows run ` + +Runs a flow **file** locally — documented as available on Postman **Enterprise** +plans, and requires `postman login`. Inputs work as on `trigger`; the rest is +execution and reporting. Takes the path positionally; a bad path fails with +`Error: Flow file not found: ` and exit 1. + +| Flag | Notes | +| --- | --- | +| `-i, --input ` | Repeatable. | +| `-f, --input-file ` | Repeatable. | +| `-s, --scenario ` | Pre-built scenario as inputs; `-i`/`-f` override values. | +| `-e, --environment ` | Postman environment file, JSON or YAML. | +| `--working-dir ` | Working directory for the run. | +| `--workspace ` | **Required for flows containing connector blocks.** | +| `--output ` | Save execution result to file. `json` only. | +| `--reporters ` | Save a test results report. `html` only. | +| `-x, --suppress-exit-code` | Overrides the run's exit code. Defeats CI gating. | +| `--verbose` | Per-request detail: method, URL, assertions. | +| `--no-truncate` | Full output, no truncated long values. | +| `--no-report-events` | Don't send analytics. `--report-events` exists for compatibility; analytics are on by default. | + +### BETA: dataset iteration + +Runs the flow once per row of a dataset view. All three are marked `[BETA]` in +the CLI's own help — confirm against live `-h` before relying on them. + +| Flag | Notes | +| --- | --- | +| `--iteration-data-dataset ` | Local `.dataset.yaml` path or a cloud dataset id (cloud requires login). **Requires `--iteration-data-view`.** | +| `--iteration-data-view ` | The view within that dataset whose rows drive the run. | +| `-m, --map-column ` | Repeatable. Binds a flow input to a dataset column. Inputs whose name already matches a column bind automatically, so only map the mismatches. | +| `--no-insecure-file-read` | Blocks reading dataset files outside the working directory. | + +## `flows list-runs` + +| Flag | Notes | +| --- | --- | +| `-w, --workspace ` | **Required**, same as on `list`. | +| `-f, --flow ` | Filter sessions to one flow. | +| `-r, --range ` | Time range, e.g. `30m`, `2h`, `3d`. **Default `1h`** — widen it before concluding a run is missing. | + +## `flows get-run` + +| Flag | Notes | +| --- | --- | +| `-r, --run-id ` | **Required.** The id `trigger` or `list-runs` reported. Shapes vary across Postman's own material (`session-abc123`, `main/1a123ab1`) — pass it verbatim rather than reformatting. | +| `-l, --logs` | Detailed event log. Off by default. | +| `--filter ` | Repeatable. Matches a block ID **prefix**, not an exact id. | diff --git a/skills/generate-spec/SKILL.md b/skills/generate-spec/SKILL.md deleted file mode 100644 index 8ce276f..0000000 --- a/skills/generate-spec/SKILL.md +++ /dev/null @@ -1,183 +0,0 @@ ---- -name: generate-spec -description: Generate or update an OpenAPI 3.0 spec from code. Use when the user wants to create, update, or write an OpenAPI/Swagger spec, API definition, or API documentation from their codebase. ---- - -You are an API specification assistant that generates and updates OpenAPI 3.0 specifications by analyzing the user's codebase. - -## When to Use This Skill - -Use this skill when the user wants to generate, create, or update an OpenAPI/Swagger spec or API definition from their existing routes and endpoints. - -A reference file in this skill's directory, `references/spec-template.md`, contains the full OpenAPI structure template and example workflows. Read it with the Read tool when you reach Step 3. - ---- - -## Step 1: Discover API Endpoints in the Codebase - -Scan the project for API route definitions. Check common patterns by framework: - -**Express.js / Node.js:** -```bash -# Find route files -find . -type f \( -name "*.js" -o -name "*.ts" \) -not -path "*/node_modules/*" | head -30 -``` -Look for: `app.get()`, `app.post()`, `router.get()`, `router.post()`, `@Get()`, `@Post()` (NestJS) - -**Python (Flask/Django/FastAPI):** -```bash -find . -type f -name "*.py" -not -path "*/.venv/*" -not -path "*/venv/*" | head -30 -``` -Look for: `@app.route()`, `@router.get()`, `path()`, `url()`, `@app.get()` (FastAPI) - -**Go:** -```bash -find . -type f -name "*.go" -not -path "*/vendor/*" | head -30 -``` -Look for: `http.HandleFunc()`, `r.GET()`, `e.GET()` (Echo), `router.Handle()` - -**Java (Spring):** -```bash -find . -type f -name "*.java" | head -30 -``` -Look for: `@GetMapping`, `@PostMapping`, `@RequestMapping`, `@RestController` - -**Ruby (Rails):** -```bash -find . -type f -name "routes.rb" -o -name "*controller*.rb" | head -20 -``` -Look for: `get`, `post`, `resources`, `namespace` - -Read the relevant source files to extract: -- HTTP methods (GET, POST, PUT, PATCH, DELETE) -- URL paths and path parameters -- Query parameters -- Request body schemas (from validation, types, or models) -- Response schemas (from return types, serializers, or examples) -- Authentication requirements -- Status codes - ---- - -## Step 2: Check for Existing Spec - -Look for an existing OpenAPI spec to update: - -```bash -# Check Postman specs directory -ls postman/specs/**/*.yaml postman/specs/**/*.yml postman/specs/**/*.json 2>/dev/null - -# Check common root locations -ls openapi.yaml openapi.yml openapi.json swagger.yaml swagger.yml swagger.json api-spec.yaml 2>/dev/null -``` - -**If an existing spec is found:** -- Read it to understand current state -- Identify what's changed (new endpoints, modified schemas, removed routes) -- Update it preserving existing descriptions, examples, and custom fields -- Tell user what was added/changed/removed - -**If no spec exists:** -- Create a new one at `postman/specs/openapi.yaml` (Postman's standard location) -- Create the `postman/specs/` directory if needed - ---- - -## Step 3: Generate the OpenAPI 3.0 Spec - -Read `references/spec-template.md` for the full YAML structure template, then build a valid OpenAPI 3.0 specification in YAML format following these rules: - -1. **Derive from code, don't guess** — Only include endpoints that actually exist in the codebase -2. **Extract real schemas** — Use model definitions, TypeScript types, Pydantic models, or struct definitions to build component schemas -3. **Include all status codes** — Add response codes the endpoint actually returns (from error handling in code) -4. **Use $ref for shared schemas** — Define models once in `components/schemas` and reference them -5. **Group with tags** — Use tags based on route file grouping or resource names -6. **operationId** — Generate unique camelCase IDs like `getUsers`, `createUser`, `deleteUserById` -7. **Detect auth** — If middleware checks auth, add security requirements to those endpoints -8. **Port detection** — Find the server port from config files, env files, or code constants - ---- - -## Step 4: Write the Spec File - -Write the spec to the appropriate location: - -- **If updating**: Write to the existing spec file path -- **If creating new**: Write to `postman/specs/openapi.yaml` - - Create `postman/specs/` directory if it doesn't exist - -Tell the user exactly where the file was written. - ---- - -## Step 5: Validate the Spec with Postman CLI - -**Always validate using the Postman CLI.** This checks for syntax errors, governance rules, and security issues configured for the team's workspace. - -**Basic lint:** -```bash -postman spec lint ./postman/specs/openapi.yaml -``` - -**Fail on warnings too (stricter):** -```bash -postman spec lint ./postman/specs/openapi.yaml --fail-severity WARNING -``` - -**Output as JSON for detailed parsing:** -```bash -postman spec lint ./postman/specs/openapi.yaml --output JSON -``` - -**Apply workspace governance rules:** -```bash -postman spec lint ./postman/specs/openapi.yaml --workspace-id -``` - -If the workspace ID is available in `.postman/resources.yaml`, use it to apply the team's governance rules. - -**Fix-and-relint loop:** -1. Run `postman spec lint` -2. Parse the error/warning output (line numbers, severity, descriptions) -3. Fix every issue in the spec -4. Re-run `postman spec lint` until clean — no errors AND no warnings -5. Do not consider the spec complete until it passes linting - -If Postman CLI is not installed, tell the user: "Install Postman CLI (`npm install -g postman-cli`) and run `postman spec lint` to validate against governance and security rules." - ---- - -## Step 6: Report Results - -Report concisely what was created or changed: the file path, endpoints documented (count and list), schemas defined, changes from the previous spec (added/updated/removed) when updating, and the validation result. - ---- - -## Error Handling - -**No API routes found:** -"Could not find API route definitions in the codebase. What framework are you using? Point me to the files containing your route definitions." - -**Unsupported framework:** -"I couldn't auto-detect the framework. Please tell me which files contain your API routes and I'll generate the spec from those." - -**Validation failures:** -Parse errors from `postman spec lint`, fix them in the spec, and re-validate. - -**CLI not installed (for validation):** -"Spec created successfully. Install Postman CLI (`npm install -g postman-cli`) and run `postman spec lint ./postman/specs/openapi.yaml` to validate." - ---- - -## Important Notes - -- Always generate OpenAPI 3.0.3 format (widely supported, compatible with Postman) -- Use YAML format (more readable than JSON for specs) -- Derive everything from actual code — never fabricate endpoints or schemas -- Preserve existing descriptions and examples when updating a spec -- Use `$ref` references to components/schemas for reusable models -- Include realistic examples in schemas when the code provides default values or test data -- **Always run `postman spec lint`** after creating or updating a spec — do not skip this step -- The spec must pass linting with zero errors and zero warnings before it is considered done -- Use `--workspace-id` with `postman spec lint` when available to enforce team governance rules -- Place new specs in `postman/specs/openapi.yaml` to align with Postman's git sync structure diff --git a/skills/generate-spec/references/spec-template.md b/skills/generate-spec/references/spec-template.md deleted file mode 100644 index 3139341..0000000 --- a/skills/generate-spec/references/spec-template.md +++ /dev/null @@ -1,118 +0,0 @@ -# OpenAPI 3.0 Spec Structure Template - -Use this structure when generating a spec. Fill every placeholder from real code — never fabricate endpoints or schemas. - -```yaml -openapi: 3.0.3 -info: - title: - version: - description: -servers: - - url: http://localhost: - description: Local development server -paths: - /endpoint: - get: - summary: - description: - operationId: - tags: - - - parameters: - - name: id - in: path - required: true - schema: - type: string - description: - responses: - "200": - description: Successful response - content: - application/json: - schema: - $ref: "#/components/schemas/ModelName" - "400": - description: Bad request - "401": - description: Unauthorized - "404": - description: Not found - "500": - description: Internal server error - post: - summary: - operationId: - tags: - - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/CreateModel" - responses: - "201": - description: Created successfully - content: - application/json: - schema: - $ref: "#/components/schemas/ModelName" -components: - schemas: - ModelName: - type: object - required: - - id - - name - properties: - id: - type: string - description: Unique identifier - name: - type: string - description: Display name - securitySchemes: - bearerAuth: - type: http - scheme: bearer - bearerFormat: JWT - apiKey: - type: apiKey - in: header - name: X-API-Key -``` - -## Example Workflows - -### Generate spec from scratch - -User: "generate an openapi spec for my API" - -1. Scan project for route definitions -2. Read route files and extract endpoints -3. Read models/types for schemas -4. Generate openapi.yaml -5. Validate with postman spec lint -6. Report: "Created spec with 12 endpoints and 5 schemas" - -### Update spec after code changes - -User: "update the spec, I added new endpoints" - -1. Read existing spec -2. Scan code for all current endpoints -3. Diff against existing spec -4. Add new endpoints, update changed ones -5. Validate -6. Report: "Added 2 new endpoints, updated 1" - -### Generate spec for specific routes - -User: "create a spec for the user routes" - -1. Find user-related route files -2. Extract only user endpoints -3. Generate focused spec -4. Validate and report diff --git a/skills/get-flow-run/SKILL.md b/skills/get-flow-run/SKILL.md deleted file mode 100644 index b6a75be..0000000 --- a/skills/get-flow-run/SKILL.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -name: get-flow-run -description: Inspect a Postman Flow run by Run ID using the Postman CLI — per-block logs, failing block, and status. Use when a trigger returned a non-2xx or the user asks why a run failed. ---- - -You are a Postman Flows assistant that inspects Flow runs using the Postman CLI. - -## The command this wraps - -```bash -POSTMAN_CLI_SOURCE=claude-code-plugin postman flows get-run --run-id [options] -``` - -Options: -- `-r, --run-id ` — **required** (this is the `x-run-id` that `trigger-flow` reported) -- `-l, --logs` — show the detailed event log -- `--filter ` — focus the event log on one or more block IDs (repeatable) - -## Step 1: Get the Run ID - -Use the Run ID the trigger skill just reported (the `x-run-id`). If you don't have one, ask the user for it. - -## Step 2: Inspect - -Start with a summary, then add `--logs` for detail: - -```bash -POSTMAN_CLI_SOURCE=claude-code-plugin postman flows get-run --run-id session-abc123 -POSTMAN_CLI_SOURCE=claude-code-plugin postman flows get-run --run-id session-abc123 --logs -``` - -Narrow to a suspect block: -```bash -POSTMAN_CLI_SOURCE=claude-code-plugin postman flows get-run --run-id session-abc123 --logs --filter blockId1 -``` - -## Step 3: Report - -Parse the output and report, rather than dumping raw logs: -- **which block failed and why** (the failing block + reason) -- the **run status** - -Example: -``` -Run session-abc123 — failed - Failing block: "HTTP Request (Get Orders)" - Reason: downstream returned 504 after 10s timeout - Status: error -Suggestion: the upstream API timed out — retry, or raise the request timeout. -``` - ---- - -Read `references/flows-cli-baseline.md` for CLI prefixing, credential reuse, and error handling rules. - -This is a read-only operation — no confirmation needed. If the Run ID is not found, confirm it with the user (runs may take a moment to appear). diff --git a/skills/get-flow-run/references/flows-cli-baseline.md b/skills/get-flow-run/references/flows-cli-baseline.md deleted file mode 100644 index d4d3f3c..0000000 --- a/skills/get-flow-run/references/flows-cli-baseline.md +++ /dev/null @@ -1,9 +0,0 @@ -# Flows CLI Baseline - -These rules apply to every Flows CLI skill. - -- Prefix every CLI call with `POSTMAN_CLI_SOURCE=claude-code-plugin` for telemetry attribution. -- Reuse existing `postman login` / API key credentials. Do not trigger a second authentication. -- Surface CLI errors verbatim. Do not assert access the CLI does not grant. -- **CLI not installed:** "Postman CLI is not installed. Install with: `npm install -g postman-cli`" -- **Not authenticated:** "Run `postman login` (or set `POSTMAN_API_KEY`)." diff --git a/skills/list-flows/SKILL.md b/skills/list-flows/SKILL.md deleted file mode 100644 index 2394c40..0000000 --- a/skills/list-flows/SKILL.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -name: list-flows -description: List Postman Flows in a workspace using the Postman CLI, and resolve a flow name to its 24-character ID. Use when the user asks which flows they have, or when another skill needs to resolve a flow name to an ID before deploying or triggering. ---- - -You are a Postman Flows assistant that lists Flows and resolves flow names to IDs using the Postman CLI. - -## The command this wraps - -```bash -POSTMAN_CLI_SOURCE=claude-code-plugin postman flows list --workspace [options] -``` - -Options: -- `-w, --workspace ` — **required** -- `-f, --filter ` — filter by name (name prefix or regex) -- `-s, --sort ` — sort criteria (default `updated`) -- `-p, --paginate` — page through all flows - -## Step 1: Get the workspace ID - -A workspace ID is **required**. If you don't have one, ask the user which workspace to look in. Don't fail silently. - -## Step 2: List - -```bash -POSTMAN_CLI_SOURCE=claude-code-plugin postman flows list --workspace 12345-67890-abcdef -``` - -Narrow with `--filter` when resolving a specific name: -```bash -POSTMAN_CLI_SOURCE=claude-code-plugin postman flows list --workspace 12345-67890-abcdef --filter "Checkout" -``` - -## Step 3: Report / resolve - -- When the user asked to see their flows: report flow **names + IDs** (and recent status where shown). -- When resolving a name for another skill: - - **Single match** → use that ID. - - **Multiple matches** → present the candidates (name + ID) and **ask the user to choose**. Never guess. (Edge case: ambiguous name) - - **No match** → tell the user, and offer to list all flows in the workspace so they can pick. - -Example: -``` -Flows in workspace 12345-67890-abcdef: - 1. Checkout — 6f1a2b3c4d5e6f7a8b9c0d1e (updated 2h ago) - 2. Checkout (old) — 1a2b3c4d5e6f7a8b9c0d1e2f (updated 40d ago) -Two flows match "Checkout" — which one? -``` - ---- - -Read `references/flows-cli-baseline.md` for CLI prefixing, credential reuse, and error handling rules. - -This is a read-only operation — no confirmation needed. diff --git a/skills/list-flows/references/flows-cli-baseline.md b/skills/list-flows/references/flows-cli-baseline.md deleted file mode 100644 index d4d3f3c..0000000 --- a/skills/list-flows/references/flows-cli-baseline.md +++ /dev/null @@ -1,9 +0,0 @@ -# Flows CLI Baseline - -These rules apply to every Flows CLI skill. - -- Prefix every CLI call with `POSTMAN_CLI_SOURCE=claude-code-plugin` for telemetry attribution. -- Reuse existing `postman login` / API key credentials. Do not trigger a second authentication. -- Surface CLI errors verbatim. Do not assert access the CLI does not grant. -- **CLI not installed:** "Postman CLI is not installed. Install with: `npm install -g postman-cli`" -- **Not authenticated:** "Run `postman login` (or set `POSTMAN_API_KEY`)." diff --git a/skills/performance-testing/SKILL.md b/skills/performance-testing/SKILL.md new file mode 100644 index 0000000..4ff27db --- /dev/null +++ b/skills/performance-testing/SKILL.md @@ -0,0 +1,71 @@ +--- +name: performance-testing +description: Load-tests a collection with concurrent virtual users, a chosen load profile, and pass/fail thresholds on latency or error rate — run locally or on Postman's cloud runners. Use when the user asks to "load test this API," "run a performance test," "check how this holds up under load," or "benchmark this collection." Covers `postman performance run`. This generates real traffic against a real target — confirm the target and scale before running, the same way any action with effects outside this session gets confirmed. +--- + +# Performance Testing + +## Overview + +`performance run ` is not `collection run` with more +iterations — it's a dedicated load-test mode: many virtual users hitting the +collection concurrently for a set duration, shaped by a load profile, scored +against thresholds you define, on infrastructure you choose. The collection +under test is authored the normal way — see the `collection-schema-v3` skill +if it needs edits before the load test is meaningful (e.g. an assertion +that would fail every VU's request identically). + +## Core knowledge + +- **Load profile is what you're actually testing.** `fixed` holds steady + concurrency (does this hold up at N users, sustained); `ramp-up` increases + gradually (where does it start to degrade); `spike` bursts suddenly (does + a sudden surge break it); `peak` sustains near-maximum load (does it + survive staying there). Pick based on the failure mode being probed, not + by default. +- **`--runner` chooses where load originates.** `local` runs from the + current machine/CI runner — bounded by its own resources, fine for + internal or low-scale targets. `postman-cloud` runs from Postman's + infrastructure — needed for realistic external-scale load, or once local + resources would cap the achievable VU count. `postman-cloud-static-ip` + is the same, from a static-IP range — needed when the target allowlists + by IP. +- **`--pass-if "less_than(p95, 500)"` turns a load test into a gate.** + Metrics: `avg`, `p90`, `p95`, `p99`, `error_rate`, `rps`. Checked after the + run completes, not enforced live — a bad configuration still generates its + full load before the gate fails. +- **`--use-mock` points the test at a mock instead of a real backend** — for + load-testing collection/script logic itself, or to baseline mock-only + latency and isolate app/network slowness from what the mock adds. +- **`--setup-collection`/`--teardown-collection`** (cloud runner only) run + once before/after the whole test — for provisioning or cleanup, not + per-iteration setup. +- **`--dataset-id`/`--dataset-view-id`** drive iteration data from a Postman + Dataset instead of a flat `--data-file`; `--dataset-distribution` controls + whether rows are spread round-robin, fixed, or randomly across VUs. + +## Critical Rules + +1. **Running this against a real, non-mock backend generates real load with + real consequences — confirm the target, VU count, and duration with the + user before running,** the same way any action with effects outside this + session gets confirmed. Default to a low `--vu-count` and short + `--duration` for a first run against anything live, or point it at a mock + (`--use-mock`) when the goal is testing the collection, not the backend. +2. **A `--pass-if` gate doesn't stop the load early.** The full VU count and + duration run regardless of whether the threshold will ultimately pass — + plan for that cost, don't assume a failing gate means less traffic was + sent. +3. **Cloud runners come from Postman's IP ranges.** Before assuming a + `postman-cloud` run will reach a target, check whether it's IP-allowlisted + — use `postman-cloud-static-ip` if so, rather than discovering the + mismatch as a wall of connection failures. + +## Verification + +State the actual metrics the run produced (p95, error rate, rps — whatever +the `--pass-if` checked, plus the ones it didn't) and whether the gate +passed, not just that the run completed. State which runner actually +executed it (`local`/`postman-cloud`/`postman-cloud-static-ip`) — that +determines whether the numbers reflect the target's real-world reachability +or only local-network conditions. diff --git a/skills/postman-cli/SKILL.md b/skills/postman-cli/SKILL.md deleted file mode 100644 index 94b9752..0000000 --- a/skills/postman-cli/SKILL.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -name: postman-cli -description: Postman CLI reference and git sync file structure knowledge - provides context for CLI-based commands (send-request, generate-spec, run-collection, context) ---- - -Reference knowledge for the Postman CLI and git sync file structure. This skill provides context used by the CLI commands. - -## Postman CLI Overview - -The Postman CLI (`postman-cli`) is the official command-line tool for Postman. It runs collections, validates API specs, sends requests, and integrates with CI/CD pipelines. - -### Installation and Auth - -```bash -npm install -g postman-cli -postman login -``` - -Authentication requires a valid Postman API key. Run `postman login` and follow the prompts. - -### Core Commands - -| Command | Purpose | -|---------|---------| -| `postman collection run ` | Run collection tests by cloud ID | -| `postman request ` | Send an HTTP request | -| `postman spec lint ` | Validate an OpenAPI spec | -| `postman context instructions` | Get agent workflow instructions for API discovery and code generation | -| `postman context collection get -c ` | Get a collection's structure (folders, requests) | -| `postman context request context -c -r ` | Get full request context for code generation | -| `postman login` | Authenticate with Postman | - ---- - -## Git Sync File Structure - -When a Postman workspace is connected to a git repo, it syncs using this structure: - -``` -project-root/ -├── .postman/ -│ └── resources.yaml # Maps local paths → cloud IDs -├── postman/ -│ ├── collections/ -│ │ └── My API/ # Collection (v3 folder format) -│ │ ├── .resources/ -│ │ │ └── definition.yaml # schemaVersion: "3.0", name -│ │ ├── Get Users.request.yaml -│ │ ├── Create User.request.yaml -│ │ └── Auth/ # Subfolder -│ │ └── Login.request.yaml -│ ├── environments/ -│ │ └── dev.postman_environment.json -│ └── specs/ -│ └── openapi.yaml -``` - -### resources.yaml - -Maps local collection/environment paths to their Postman cloud IDs: - -```yaml -cloudResources: - collections: - ../postman/collections/My API: 45288920-e06bf878-2400-4d76-b187-d3a9c99d6899 - environments: - ../postman/environments/dev.postman_environment.json: 45288920-abc12345-... -``` - -### Collection v3 Folder Format - -Each collection is a **directory** (not a single JSON file). It contains: -- `.resources/definition.yaml` — collection metadata -- `*.request.yaml` — individual request files -- Subdirectories for folders within the collection - -Request files contain: -```yaml -$kind: http-request -url: https://api.example.com/users -method: GET -order: 1000 -``` - ---- - -## Postman CLI vs Newman - -The Postman CLI is the **official replacement** for Newman: - -| Feature | Postman CLI | Newman | -|---------|-------------|---------| -| Maintenance | Official Postman support | Community-driven | -| Security | Digitally signed binary | Open-source | -| Governance | Enterprise API governance | Not available | -| Auth | Postman API key | No authentication | -| Spec linting | Built-in | Not available | -| HTTP requests | `postman request` command | Not available | - -Always use `postman-cli`, never Newman. diff --git a/skills/postman-context/SKILL.md b/skills/postman-context/SKILL.md deleted file mode 100644 index 46f1805..0000000 --- a/skills/postman-context/SKILL.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -name: postman-context -description: Discover, explore, install, and generate client code from APIs in Postman. Use when the user wants to find or integrate an API, explore a collection, or generate or maintain API client code — required before generating code from any Postman collection, even one already explored via MCP tools. ---- - -You are an API integration assistant that uses Postman Context to discover APIs, explore their structure, and generate accurate client code from real API definitions. - -## When to Use This Skill - -Use this skill when the user wants to find, install, or integrate an API; generate client code or a service wrapper; explore a Postman collection's structure; or list, update, or remove installed API integrations. - -**IMPORTANT:** Even if you've already explored a collection using MCP tools (`getCollection`, `getCollectionRequest`, etc.), you MUST still use this skill before generating client code. The `getRequestCodeContext` tool provides structured context specifically designed for accurate code generation, and the code-generation rules in this skill must be followed. - -**Do NOT use this skill when:** -- User wants to send a live HTTP request (use `send-request`) -- User wants to run collection tests (use `run-collection`) -- User wants to generate an OpenAPI spec from their own code (use `generate-spec`) - -## Reference Files - -Detailed rules live in separate files inside this skill's directory. Read them with the Read tool only when you reach the step that needs them: - -- `references/code-generation.md` — REQUIRED before generating any client code (Step 3) -- `references/maintenance.md` — REQUIRED before listing, updating, or removing installed requests (Step 4) - ---- - -## Prerequisites - -The Postman MCP Server must be connected. If MCP tools aren't available, tell the user: "Run `/postman:setup` to configure the Postman MCP Server." - ---- - -## Concepts - -In Postman, a **collection** is a container of API requests organized into folders. Each **request** defines a single API call — method, URL, headers, body, auth, and example responses. Collections live in **workspaces**, which can be personal, team, or public. - ---- - -## Which MCP Tools to Use - -This skill uses the **context MCP tools** (`*Context` tools), not the generic CRUD tools. The context tools return AI-optimized markdown output designed for understanding APIs and generating code. Always prefer them over the generic equivalents: - -| Purpose | Use this (context tool) | NOT this (generic tool) | -|---|---|---| -| Get collection structure | `getCollectionContext` | `getCollection` | -| Get request details | `getRequestContext` | `getCollectionRequest` | -| Get full code-gen context | `getRequestCodeContext` | *(no equivalent)* | -| Get folder details | `getFolderContext` | `getCollectionFolder` | -| Get response example | `getResponseContext` | `getCollectionResponse` | -| Get workspace details | `getWorkspaceContext` | `getWorkspace` | -| List workspaces | `getWorkspacesContext` | `getWorkspaces` | -| Get environment | `getEnvironmentContext` | `getEnvironment` | -| List workspace environments | `getWorkspaceEnvironmentsContext` | `getEnvironments` | - -The generic tools (`getCollection`, `getCollectionRequest`, etc.) are for CRUD operations — creating, updating, and deleting Postman entities. Use them only when modifying Postman data, not when exploring or generating code. - ---- - -## How Users Start - -Users don't typically start by thinking about collections and request IDs. They start with intent: "build me a dashboard that shows recent chargebacks" (figure out which APIs and requests are needed), "find me a good email API" (search, explore, help them choose), "what requests do we have installed?" or "are my integrations up to date?" (manage existing integrations). - -Meet the user where they are. The workflow below describes the full path from search to installed request, but the user may enter at any point. - ---- - -## Workflow - -### Step 1: Find the API - -**Public APIs:** For well-known third-party APIs, use `searchPostmanElements` with `ownership: external` to search the public API network. Each result includes the collection UID, collection name, workspace ID, publisher name, and whether the publisher is verified. When presenting results, include Postman links (`https://go.postman.co/collection/`) so the user can explore in Postman if they want. - -**Internal / Private APIs:** For team APIs, private APIs, or the user's own collections, use the existing search tool or `getWorkspacesContext` to list workspaces, then `getWorkspaceContext` to see a workspace's collections. If the user says "my" (e.g. "my APIs", "my workspaces"), filter to personal workspaces only — this dramatically reduces noise when the team has many workspaces. - -**Choosing and comparing APIs:** When the user expresses a need like "I need an email API," don't just search — help them evaluate. Search for relevant collections, explore what each one offers (folder structure, endpoints, auth approach), and present a comparison grounded in real API definitions rather than general knowledge. - -### Step 2: Explore the Collection - -Once you've identified one or more collections that match the user's intent, explore their structure using the context tools from the table above. Drill into specific requests or folders as needed — fetch only what's relevant rather than dumping entire collections. Help the user understand what's available and decide which requests they need. Explain what "installing a request" means: fetching the full API context from Postman and generating a code file in the project that faithfully represents that API endpoint. - -### Step 3: Install Requests (Generate Code) - -**User confirmation required:** Do NOT install requests without explicit user confirmation. After exploring a collection, present the available folders and requests, then ask the user which ones they want to install. Never assume the user wants all of them. - -For each request the user wants to install, use `getRequestCodeContext` to fetch the full context. This returns a comprehensive document with collection metadata, request details (method, URL, params, headers, auth, body), parent folder documentation, response examples, and environment variables. No code generation can proceed without it. - -**Read `references/code-generation.md` now** and generate client code following its rules exactly. Once a request's code has been generated, consider it "installed." - -### Step 4: Maintain Installed Requests - -**Read `references/maintenance.md`** and follow its rules to list installed requests, check for upstream changes, find unused requests, and remove installed requests. - ---- - -## Linking to Postman - -Any collection or request can be linked to directly using its UID: - -- **Collection:** `https://go.postman.co/collection/` -- **Request:** `https://go.postman.co/request/` - -When the user asks for a link, provide it. When presenting search results, installed request details, or update reports, include links proactively so the user can jump straight to Postman. - ---- - -## Error Handling - -**MCP not configured:** -"Run `/postman:setup` to configure the Postman MCP Server." - -**401 Unauthorized:** -"Your Postman API key was rejected. Generate a new one at https://postman.postman.co/settings/me/api-keys and run `/postman:setup`." - -**404 or empty response:** -"Could not find the requested resource. Check that the collection/request ID is correct." - ---- - -## Important Notes - -- Context tools return markdown — parse and use the content, don't just dump it -- Always prefer real API definitions from Postman Context over guessing from training data -- Do not expose sensitive data like tokens in output diff --git a/skills/postman-context/references/code-generation.md b/skills/postman-context/references/code-generation.md deleted file mode 100644 index 793caf1..0000000 --- a/skills/postman-context/references/code-generation.md +++ /dev/null @@ -1,129 +0,0 @@ -# Code Generation Rules - -Read this file in full before generating any client code from a Postman request. - -## Key Principle - -The generated request file must be a faithful representation of the Postman request. Do not add validation, business logic, or constraints beyond what the API defines. That logic belongs in calling code at a higher level. - -## Match the Project - -Before generating, analyze the target project. Follow this priority: - -1. **What the project already does.** Match existing patterns: HTTP client library, module format, error handling, naming conventions, auth patterns, directory structure. If the project uses `axios`, use `axios`. -2. **What is idiomatic for the language/framework.** If no existing pattern exists, use the standard or most common approach. -3. **Sensible defaults.** If neither applies, make a reasonable choice. - -Only deviate from project patterns if the user explicitly asks. - -## File Placement - -1. Search the project for existing installed requests (files containing "Generated by Postman Code" in a header comment). If found, follow the same directory pattern. -2. If no existing installed requests, decide where to place files: - -**Find the root directory.** Look at the project to determine where API client code, service layers, or external integrations belong. Common locations include `services/`, `lib/`, `clients/`, `src/api/`, or their language-specific equivalents. Use the most conventional location for the project's language and framework. Only if no pattern exists, choose a sensible default. - -**Use the collection name as the directory name.** Slugify the collection name for the directory — e.g. a collection called "Stripe API" becomes `stripe-api/`. This directory may already exist if the user has previously installed requests from the same collection. If the user integrates APIs from multiple collections, each collection gets its own sibling directory under the root (e.g. `services/stripe-api/`, `services/sendgrid-api/`). - -**Aim to preserve the collection's folder structure as directories.** Folders in the Postman collection become subdirectories inside the collection directory, and each request becomes a file. Some of these directories may already exist from previously installed requests — only create what's missing. In languages where directories are lightweight (JS/TS, Python, Ruby), this direct mapping works well. In languages where directory depth carries semantic weight — Java/Kotlin (folders = package segments) and C#/.NET (folders = namespace segments) — prefer flatter structures, e.g. a single package for the collection with files named by request rather than a nested directory per folder. - -**Normalize names for the filesystem.** Convert Postman object names to safe directory and file names. In most languages, lowercase and replace non-alphanumeric runs with `-` (e.g. "Stripe API" becomes `stripe-api`). In languages where directory or file names must be valid identifiers — such as Java/Kotlin packages or C#/.NET namespaces — use the language's naming convention instead (e.g. `stripeapi` or `stripe_api`). If two sibling items resolve to the same name, append `-1`, `-2`, etc. (or `_1`, `_2` where hyphens aren't valid). - -## Required File Header - -Every installed request file MUST start with a header comment (in the language's comment syntax). This header is how the system identifies and manages installed requests. - -Required fields: - -- The phrase "Generated by Postman Code" (used for file discovery) -- Collection name and Collection UID -- Request path (folder hierarchy > request name) and Request UID -- Request modified-at timestamp (for update detection) - -Template: - -``` -Generated by Postman Code - -Collection: -Collection UID: - -Request: -Request UID: -Request modified at: -``` - -## Variables File - -If the collection has collection-level variables or the workspace has environments, generate a variables file at the root of the collection directory. - -The purpose of this file is to centralize variable values so the caller can select an environment and pass resolved values to client functions. Structure it as a mapping with: - -- A `collection` key for collection-level variables -- A key for each environment, using the exact environment name from Postman (do not normalize names) - -Use the language's idiomatic construct for a string-keyed mapping — an exported object in JS/TS, a dictionary in Python, a `Map` or similar in Java/C#, a map in Go, etc. Environment names from Postman are arbitrary strings and may not be valid identifiers, so prefer structures that support string keys over static fields or enum members. - -Example (TypeScript): - -```typescript -export const variables = { - collection: { - apiVersion: "v2", - }, - Production: { - baseUrl: "https://api.example.com", - apiKey: "", - }, - Staging: { - baseUrl: "https://api-staging.example.com", - apiKey: "", - }, -}; -``` - -The caller of the generated client is responsible for selecting an environment, merging collection and environment variables, binding secrets, and passing the result to client functions. Don't do that work here. - -## Function Structure - -Generate a single exported function per API endpoint: - -- Accept all dynamic values as explicit parameters (base URL, path variables, query params, body data, auth credentials) -- Do not hardcode variable values — the caller passes them in -- Replace Postman `{{variable}}` placeholders with function parameters -- Accept base URL and URL-related variables as function parameters -- Encode path parameters and query parameters properly -- Build the complete URL from base URL + path - -## Authentication - -Implement the auth scheme from the context document (request-level, folder-level, or collection-level inheritance): - -- Accept credentials as function parameters — never hardcode them -- Support the auth type as documented (API key, Bearer token, Basic auth, etc.) - -## Response Handling - -- Parse the response payload -- If the context includes response examples, add explicit error handling for each documented status code (e.g., if the request has a 404 example, include specific 404 handling) -- Generate typed definitions for request bodies, parameters, and response shapes. Prefer the language's strongest available typing mechanism (e.g., TypeScript interfaces, JSDoc `@typedef` in JavaScript, Python TypedDicts or dataclasses, Go structs, Ruby Structs, PHP typed classes). Only fall back to documenting shapes in comments if the language has no typing or structured-object support at all. -- Follow project conventions for error handling patterns (logging, exception classes, error codes) -- Return or throw errors with meaningful context - -## Documentation - -- Add standard docstrings in the language's convention (JSDoc/TSDoc, Python docstrings, etc.) -- Include the request description from the context document if present -- Document all parameters, return types, and possible errors - -## Extracting Shared Code - -After generating multiple client files for a collection, consolidate duplicated types, auth helpers, and utility functions so they are defined once. - -- Identify duplicated code across clients in the same collection -- Extract shared code and colocate it with the collection's client files using whatever mechanism is idiomatic for the language — a `shared/` subdirectory, a sibling module, a `common` subpackage, unexported helpers in the same package, etc. -- Keep shared code scoped to a single collection by default — only share across collections if the user explicitly asks - -## Quality Verification - -Ensure generated code is lintable, production-ready, type-safe in typed languages, and follows security best practices (no hardcoded secrets, proper input validation). diff --git a/skills/postman-context/references/maintenance.md b/skills/postman-context/references/maintenance.md deleted file mode 100644 index 5046be5..0000000 --- a/skills/postman-context/references/maintenance.md +++ /dev/null @@ -1,29 +0,0 @@ -# API Maintenance Rules - -Installed requests include metadata linking them back to their source Postman collection and request. Use these rules to help users keep their integrations current. - -## Listing Installed Requests - -When the user wants to see what's installed, search the project for files containing "Generated by Postman Code" in a comment within the first 15 lines. Parse each file's header to extract: - -- Collection name and Collection UID -- Request path and Request UID -- Request modified-at timestamp - -Present a table showing local file path (relative to project root), collection name, request path, and last modified timestamp. - -## Checking for Updates - -When the user wants to check for API changes, scan for installed requests as above, then for each one use `getRequestContext` to fetch the current request details. Compare the updated-at timestamp from the response to the `Request modified at` timestamp in the file header. Report a table of all installed requests with their status (current or outdated). For any outdated requests, ask the user if they want to regenerate. For confirmed updates, use `getRequestCodeContext` to re-fetch context and regenerate the file in place, matching the existing code style and updating the header timestamp. - -## Finding Unused Requests - -When the user wants to clean up, scan for installed requests, then for each one search the rest of the project for imports, requires, or other references to that file (by module path, relative path, or exported function name). Report any requests with zero references. Offer to remove them — for confirmed removals, delete the file and remove empty parent directories up the tree. - -## Removing Installed Requests - -When the user wants to remove a specific request, identify the file by path, request name, or request UID. If ambiguous, list installed requests first and ask which one. Then: - -1. Delete the request file. -2. Remove empty parent directories up the tree until reaching one with contents. -3. Search the project for imports or requires referencing the deleted file. Warn the user about any broken references so they can update their code. diff --git a/skills/postman-knowledge/SKILL.md b/skills/postman-mcp-server/SKILL.md similarity index 74% rename from skills/postman-knowledge/SKILL.md rename to skills/postman-mcp-server/SKILL.md index 1729589..2b96125 100644 --- a/skills/postman-knowledge/SKILL.md +++ b/skills/postman-mcp-server/SKILL.md @@ -1,5 +1,5 @@ --- -name: postman-knowledge +name: postman-mcp-server description: Postman concepts and MCP tool guidance. Loaded when working with Postman MCP tools to make better decisions about tool selection and workarounds. user-invocable: false --- @@ -8,6 +8,8 @@ user-invocable: false Reference for Postman concepts and MCP tool selection. Use this context when working with Postman MCP tools to make better decisions. +See `references/setup.md` for how to to setup postman mcp server and auth. + ## Core Concepts - **Collection:** A group of API requests organized in folders. The primary unit of work in Postman. Contains requests, examples, tests, and documentation. @@ -50,4 +52,20 @@ Reference for Postman concepts and MCP tool selection. Use this context when wor **Learning Center:** `searchLearningCenter` (Full mode only — searches Postman product docs for how-to guidance) **User:** `getAuthenticatedUser` -See `mcp-limitations.md` in this skill folder for known limitations and workarounds. +See `references/mcp-limitations.md` for known limitations and workarounds. + +## Workflows + +Each reference below is a full MCP-tool workflow for one goal — the tool +call sequence, what to present at each step, and error handling. Reach for +one once the Decision Guide above has picked a goal; they assume MCP tools +only, no `postman` CLI. + +- `references/setup.md` — first-run auth (OAuth or API key) and workspace verification. +- `references/search.md` — discover APIs across workspaces with `searchPostmanElements`. +- `references/sync.md` — create/update collections from specs, or sync a spec from collection changes. +- `references/mock.md` — create a mock server from a collection or spec. +- `references/test.md` — run collection tests and diagnose failures. +- `references/docs.md` — generate, improve, and publish API documentation. +- `references/security.md` — audit a spec or collection against the OWASP API Top 10. +- `references/learn.md` — search the Postman Learning Center for how-to guidance. diff --git a/commands/docs.md b/skills/postman-mcp-server/references/docs.md similarity index 100% rename from commands/docs.md rename to skills/postman-mcp-server/references/docs.md diff --git a/commands/learn.md b/skills/postman-mcp-server/references/learn.md similarity index 97% rename from commands/learn.md rename to skills/postman-mcp-server/references/learn.md index 650770c..b8f9e89 100644 --- a/commands/learn.md +++ b/skills/postman-mcp-server/references/learn.md @@ -20,7 +20,7 @@ This command uses `searchLearningCenter`, which is only exposed when the Postman ### Step 1: Search -Call `searchLearningCenter` with a focused `query` derived from the user's question. Prefer the product vocabulary from `postman-knowledge` (mock server, environment, monitor, collection variable, etc.) over the user's exact phrasing. +Call `searchLearningCenter` with a focused `query` derived from the user's question. Prefer the product vocabulary from `postman-mcp-server` (mock server, environment, monitor, collection variable, etc.) over the user's exact phrasing. - Turn a broad request into a specific query — "how to create a mock server", "write a test script", "set a collection variable", "schedule a monitor". - If results are thin or off-target, refine: try a different feature term, split a multi-part question into separate searches, or broaden a narrow query. diff --git a/skills/postman-knowledge/mcp-limitations.md b/skills/postman-mcp-server/references/mcp-limitations.md similarity index 100% rename from skills/postman-knowledge/mcp-limitations.md rename to skills/postman-mcp-server/references/mcp-limitations.md diff --git a/commands/mock.md b/skills/postman-mcp-server/references/mock.md similarity index 100% rename from commands/mock.md rename to skills/postman-mcp-server/references/mock.md diff --git a/commands/search.md b/skills/postman-mcp-server/references/search.md similarity index 100% rename from commands/search.md rename to skills/postman-mcp-server/references/search.md diff --git a/commands/security.md b/skills/postman-mcp-server/references/security.md similarity index 100% rename from commands/security.md rename to skills/postman-mcp-server/references/security.md diff --git a/commands/setup.md b/skills/postman-mcp-server/references/setup.md similarity index 100% rename from commands/setup.md rename to skills/postman-mcp-server/references/setup.md diff --git a/commands/sync.md b/skills/postman-mcp-server/references/sync.md similarity index 100% rename from commands/sync.md rename to skills/postman-mcp-server/references/sync.md diff --git a/commands/test.md b/skills/postman-mcp-server/references/test.md similarity index 100% rename from commands/test.md rename to skills/postman-mcp-server/references/test.md diff --git a/skills/run-collection/SKILL.md b/skills/run-collection/SKILL.md deleted file mode 100644 index 50a0438..0000000 --- a/skills/run-collection/SKILL.md +++ /dev/null @@ -1,208 +0,0 @@ ---- -name: run-collection -description: Run Postman collection tests using the Postman CLI. Use when the user wants to run collection tests, execute API test suites, or verify changes after editing code. ---- - -You are an API testing assistant that runs Postman collection tests using the Postman CLI. - -## When to Use This Skill - -Trigger this skill when: -- User asks to "run tests" or "run my collection" -- User wants to "verify changes" or "check if tests pass" -- User says "run postman tests" or "execute collection" -- After code changes that may affect API behavior -- User wants to validate their API endpoints work correctly - ---- - -## Understanding the Collection Format - -Postman collections synced via git use the **v3 folder format**: - -``` -postman/collections/ -├── My API Tests/ # Collection folder (folder name = collection name) -│ ├── .resources/ -│ │ └── definition.yaml # Collection metadata (schemaVersion: "3.0", name) -│ ├── Get Users.request.yaml # Individual request files -│ ├── Create User.request.yaml -│ └── Auth/ # Subfolder for grouped requests -│ └── Login.request.yaml -``` - -The `.postman/resources.yaml` file maps local collection folders to their cloud IDs: - -```yaml -cloudResources: - collections: - ../postman/collections/My API Tests: 45288920-e06bf878-2400-4d76-b187-d3a9c99d6899 -``` - ---- - -## Step 1: Find Collections and Their IDs - -1. List collection folders in `postman/collections/`: -```bash -ls postman/collections/ -``` - -2. Read `.postman/resources.yaml` to get the cloud ID for each collection: -```bash -cat .postman/resources.yaml -``` - -The `cloudResources.collections` section maps local paths to collection IDs. Match the collection folder name to get its ID. - -**If no collections found:** -- Tell user: "No Postman collections found in `postman/collections/`. Connect your repo to a Postman workspace to sync collections." -- Stop here - -**If no ID found in resources.yaml:** -- Tell user the collection exists locally but has no cloud ID mapped — they may need to sync with Postman - -**If one collection found:** -- Use it directly, tell user which collection you're running - -**If multiple collections found:** -- List them and ask user which one to run - ---- - -## Step 2: Run the Collection - -The Postman CLI runs collections by **collection ID**: - -```bash -postman collection run -``` - -For example: -```bash -postman collection run 45288920-e06bf878-2400-4d76-b187-d3a9c99d6899 -``` - -**With environment:** -```bash -postman collection run \ - -e ./postman/environments/.json -``` - -**With options:** -```bash -# Stop on first failure -postman collection run --bail - -# With request timeout -postman collection run --timeout-request 10000 - -# Override environment variables -postman collection run \ - --env-var "base_url=http://localhost:3000" - -# Run specific folder or request within collection -postman collection run -i -``` - -Always show the exact command being executed before running it. - ---- - -## Step 3: Check for Environment Files - -Look for environment files (do NOT add `-e` flag unless one exists): - -```bash -ls postman/environments/ 2>/dev/null -``` - -- If environment files exist, ask user if they want to use one -- If no environment files, proceed without `-e` flag - ---- - -## Step 4: Parse and Report Results - -### Successful run (all tests pass) -``` -All tests passed - -Collection: My API Tests -Results: 47/47 assertions passed -Requests: 10 executed, 0 failed -Duration: 2.5s -``` - -### Failed run (some tests fail) -Parse the CLI output to extract: -- Total assertions vs failed assertions -- Failed test names and error messages -- Which requests failed -- Status codes received vs expected - -Report format: -``` -3 tests failed - -Collection: My API Tests -Results: 44/47 assertions passed, 3 failed -Requests: 10 executed, 2 had failures -Duration: 2.5s - -Failures: -1. "Status code is 200" — POST /api/users - Expected 200, got 500 - -2. "Response has user ID" — POST /api/users - Property 'id' not found in response - -3. "Response time < 1000ms" — GET /api/products - Response time was 1245ms -``` - ---- - -## Step 5: Analyze Failures and Fix - -When tests fail: - -1. **Identify the root cause** — Read the error messages and relate them to recent code changes -2. **Check the relevant source code** — Read the files that handle the failing endpoints -3. **Suggest specific fixes** — Propose code changes to fix the failures -4. **Apply fixes** (with user approval) -5. **Re-run the collection** to verify fixes worked - -Repeat the fix-and-rerun cycle until all tests pass or user decides to stop. - ---- - -## Error Handling - -**CLI not installed:** -"Postman CLI is not installed. Install with: `npm install -g postman-cli`" - -**Not authenticated:** -"Postman CLI requires authentication. Run: `postman login`" - -**Collection not found:** -"Collection not found. Check that your collections are synced in `postman/collections/` and the cloud ID exists in `.postman/resources.yaml`." - -**Server not running:** -"Requests are failing with connection errors. Make sure your local server is running." - -**Timeout:** -"Requests are timing out. Check server performance or increase timeout with `--timeout-request`." - ---- - -## Important Notes - -- Collections use the **v3 folder format** — each collection is a directory, not a single JSON file -- Run collections by **ID** using `postman collection run ` -- Get the collection ID from `.postman/resources.yaml` under `cloudResources.collections` -- Always show the exact command being executed -- Parse the CLI output to extract structured results (don't just dump raw output) -- After failures, read the relevant source code before suggesting fixes -- Do NOT add `-e` or `--environment` flags unless an environment file exists -- Don't expose sensitive data from test output (tokens, passwords) diff --git a/skills/send-request/SKILL.md b/skills/send-request/SKILL.md deleted file mode 100644 index 6fa1077..0000000 --- a/skills/send-request/SKILL.md +++ /dev/null @@ -1,175 +0,0 @@ ---- -name: send-request -description: Send HTTP requests using the Postman CLI. Use when the user wants to send a request, call or test an HTTP endpoint, or quickly try an API. ---- - -You are an API testing assistant that helps send HTTP requests using the Postman CLI. - -## When to Use This Skill - -Trigger this skill when: -- User asks to "send a request" or "make a request" -- User wants to "test an endpoint" or "hit the API" -- User says "call the API" or "try the endpoint" -- User wants to verify an endpoint is working -- User asks to test a specific URL - ---- - -## Step 1: Determine Request Details - -**If user provides a URL directly:** -- Extract method (default to GET if not specified) -- Extract URL -- Note any headers, body, or auth mentioned - -**If user wants to send a request from a collection:** - -Collections use the **v3 folder format** — each collection is a directory containing `*.request.yaml` files: - -``` -postman/collections/ -├── My API/ -│ ├── .resources/ -│ │ └── definition.yaml # schemaVersion: "3.0", name -│ ├── Get Users.request.yaml # method: GET, url: https://... -│ ├── Create User.request.yaml -│ └── Auth/ -│ └── Login.request.yaml -``` - -Each `*.request.yaml` contains: -```yaml -$kind: http-request -url: https://api.example.com/users -method: GET -order: 1000 -``` - -To find requests from collections: -1. List collection folders in `postman/collections/` -2. Read the `*.request.yaml` files to find available requests -3. Extract `method` and `url` from the matching request file -4. Ask user which request to send (if multiple match) - ---- - -## Step 2: Build the Command - -**Basic request:** -```bash -postman request "" -``` - -**With headers** (repeatable): -```bash -postman request "" \ - -H "Header-Name: value" \ - -H "Another-Header: value" -``` - -**With body** (POST/PUT/PATCH): -```bash -# Inline JSON -postman request "" -d '{"key": "value"}' - -# From file -postman request "" -d @body.json -``` - -**With form data** (repeatable, supports file upload): -```bash -postman request "" \ - -f "field=value" \ - -f "file=@path/to/file.png" -``` - -**With authentication:** -```bash -# Bearer token -postman request "" --auth-bearer-token "" - -# API Key -postman request "" --auth-apikey-key "X-API-Key" --auth-apikey-value "" - -# Basic auth -postman request "" --auth-basic-username "" --auth-basic-password "" -``` - -**With environment:** -```bash -postman request "" \ - -e ./postman/environments/.postman_environment.json -``` - -**Additional options:** -```bash -# Retry on failure -postman request "" --retry 3 --retry-delay 1000 - -# Custom timeout (default 300000ms) -postman request "" --timeout 10000 - -# Save response to file -postman request "" -o response.json - -# Response body only (no metadata) -postman request "" --response-only - -# Verbose output (full request/response details) -postman request "" --verbose - -# Debug mode -postman request "" --debug - -# Redirect control -postman request "" --redirects-max 5 -postman request "" --redirects-ignore - -# Pre-request and post-response scripts -postman request "" --script-pre-request @pre.js --script-post-request @post.js -``` - ---- - -## Step 3: Execute the Request - -Run the command and capture output. Always show the exact command being executed. - ---- - -## Step 4: Parse and Report Results - -Parse the response and report: status code, response time, and response body formatted for readability. - -For errors (4xx/5xx), suggest fixes: -- 401/403: Suggest adding auth headers -- 404: Check URL path -- 500: May be a backend issue -- Connection refused: Check if server is running - ---- - -## Error Handling - -**CLI not installed:** -"Postman CLI is not installed. Install with: `npm install -g postman-cli`" - -**Invalid URL:** -"The URL appears to be invalid. Please provide a valid HTTP/HTTPS URL." - -**Connection refused:** -"Could not connect to the server. Check if the server is running and the URL is correct." - -**Timeout:** -"Request timed out. The server may be slow or unreachable." - ---- - -## Important Notes - -- Always show the exact command being executed -- Parse and format the response for readability -- Suggest fixes for common errors (auth issues, invalid URLs) -- Collections use the v3 folder format — read `*.request.yaml` files to extract method and URL -- Don't expose or log sensitive data like tokens in output diff --git a/skills/trigger-flow/SKILL.md b/skills/trigger-flow/SKILL.md deleted file mode 100644 index 61fa1b2..0000000 --- a/skills/trigger-flow/SKILL.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -name: trigger-flow -description: Trigger (run) a deployed Postman Flow via the Postman CLI with natural-language inputs. Use when the user wants to execute a flow — handles name-to-ID resolution and deploy-then-trigger fallback. ---- - -You are a Postman Flows assistant that triggers deployed Flows using the Postman CLI. - -## The command this wraps - -```bash -POSTMAN_CLI_SOURCE=claude-code-plugin postman flows trigger [options] -``` - -Triggering fires a **deployed** flow over its webhook and returns a **Run ID** (`x-run-id`) plus the HTTP status and response body. - -Options: -- `-i, --input ` — payload values (repeatable): `-i amount=4200 -i currency=USD` -- `-f, --input-file ` — payload values from a JSON file (repeatable) -- `-q, --query ` — query parameters (repeatable) -- `--headers ` — custom headers (repeatable): `--headers X-API-Key=123` -- `-s, --scenario ` — use a named scenario from the flow definition -- `-n, --dry-run` — show the request URL + payload without sending (add `--show-secrets` to unmask tokens) -- `-r, --result` — print only the response body - -Flow IDs are 24-character hex. If you only have a name, resolve the ID first (Step 1). - ---- - -## Step 1: Resolve the flow ID - -If the user gave a **24-char ID**, use it directly. - -If the user gave a **name** (e.g. "the Checkout flow"), resolve it to an ID with the `list-flows` skill: -- You need the **workspace ID**. If you don't know it, ask the user which workspace the flow is in. -- List flows in that workspace and match the name. On a single match, use its ID. On **multiple matches**, show the candidates and ask the user to choose. - -Do not fail with "missing flow ID" — always route to resolution or ask for the workspace. - -## Step 2: Build the inputs - -Translate the user's natural-language request into CLI flags: -- "with amount=4200 and currency=USD" → `-i amount=4200 -i currency=USD` -- "pass ?version=v2" → `-q version=v2` -- "send header X-API-Key 123" → `--headers X-API-Key=123` -- "use the Staging scenario" → `-s "Staging"` - -Always show the exact command before running it. If the user wants to preview without sending, use `--dry-run`. - -## Step 3: Trigger - -```bash -POSTMAN_CLI_SOURCE=claude-code-plugin postman flows trigger 12345-67890-abcdef -i amount=4200 -``` - -On success, report back **all three**: -- **Run ID** (from the `x-run-id` header) -- **HTTP status** -- **Response body** - -Example report: -``` -Triggered the Checkout flow. - Run ID: session-abc123 - Status: 200 OK - Response: { "ok": true, "orderId": "ord_991" } -``` - -## Step 4: Handle state mismatches - -### Flow is not deployed -If the CLI reports the flow is not deployed (a 404 with a hint like `To deploy it, run: postman flows deploy `): -1. **Explain** that the flow isn't deployed yet, so it can't be triggered. -2. **Offer to deploy it** on the user's behalf using the `deploy-flow` skill — which proposes a trigger path and confirms it. -3. Deploying is a **mutating action**: proceed only after the user **explicitly confirms**. If they decline, do nothing further. -4. After a successful deploy, **re-run the trigger** and report the Run ID + status + response. - -### Trigger is disabled -If the CLI reports the trigger/target is disabled: -1. Explain the trigger is currently off. -2. Offer to enable it — a state change requiring **explicit confirmation**: - ```bash - POSTMAN_CLI_SOURCE=claude-code-plugin postman flows update --trigger on - ``` -3. After enabling (only on confirmation), trigger the flow. - -## Step 5: Handle a failing response - -If the trigger returns a **non-2xx** status, surface the **status and response body**, then offer to inspect the run: -- Offer to run the `get-flow-run` skill with the Run ID to see the failing block, reason, and status. - -``` -Trigger returned 500. - Run ID: session-def456 - Response: { "error": "downstream timeout" } -Want me to inspect the run? I can pull the per-block detail with get-flow-run for session-def456. -``` - ---- - -Read `references/flows-cli-baseline.md` for CLI prefixing, credential reuse, and error handling rules. - -Triggering an already-deployed flow is non-mutating and needs no confirmation. Deploying or enabling a trigger are state changes — confirm with the user first. diff --git a/skills/trigger-flow/references/flows-cli-baseline.md b/skills/trigger-flow/references/flows-cli-baseline.md deleted file mode 100644 index d4d3f3c..0000000 --- a/skills/trigger-flow/references/flows-cli-baseline.md +++ /dev/null @@ -1,9 +0,0 @@ -# Flows CLI Baseline - -These rules apply to every Flows CLI skill. - -- Prefix every CLI call with `POSTMAN_CLI_SOURCE=claude-code-plugin` for telemetry attribution. -- Reuse existing `postman login` / API key credentials. Do not trigger a second authentication. -- Surface CLI errors verbatim. Do not assert access the CLI does not grant. -- **CLI not installed:** "Postman CLI is not installed. Install with: `npm install -g postman-cli`" -- **Not authenticated:** "Run `postman login` (or set `POSTMAN_API_KEY`)."