Postguy
Reference

Automation tools

The JSON tool table behind postguy-cli: call rules, the run --script step format, and all 71 tools with their arguments and safety flags.

Every action the app can do to a workspace is a JSON tool. All frontends share the same tool table: the CLI today, an MCP server later. This page lists all 71 tools. It comes from the output of postguy-cli tools --json, which is the source of truth. Run it to get the schemas in machine-readable form.

postguy-cli tools            # name, safety and title, one line per tool
postguy-cli tools --json     # {"tools":[{name,title,description,inputSchema,readOnly,destructive}]}

See the CLI reference for the commands that run the tools.

How calls work

  • Arguments are one JSON object. null or no --json means {}. Any other JSON type is refused with "argument (arguments) must be a JSON object".
  • Unknown arguments are refused. The error lists what is allowed: tool: unknown argument `x`; allowed: a, b. Every schema has additionalProperties: false.
  • Missing required arguments are refused: tool: missing required argument `x` . Types are not checked up front. A wrong type fails inside the tool with a message like "argument x must be ..., got ...".
  • Error strings say what was wrong and what is allowed. The ones you will meet most:
    • unknown tool `x`; run `postguy-cli tools`
    • no workspace is open; call workspace_open first
    • collection `ID` not found in the workspace (the same shape for every entity kind)
    • PATH is outside the allowed directory ROOT: the same text whether or not the path exists.
  • Ids are opaque strings. Get them from the list tools (collection_list, env_list, run_list, ...) or from the result of a create tool. Postguy generates UUIDs. Ids from imported files can be shorter.
  • Deletes go to the workspace trash. Destructive tools are flagged destructive and move data to .trash/ instead of erasing it. history_clear, console_clear and cookies_* clear their own stores. See Workspace format.
  • Paths in arguments (path, out, data, paths) go through --root confinement when a root is set. Relative paths resolve against the root, and a path outside it is refused. Without --root, nothing is confined and relative paths resolve against the current directory.
  • Response bodies are capped at 1 MiB in tool results (request_send, response_get, response_render_body). Use response_save to get the full decoded body.
  • Cancelling: request_send, request_cancel and collection_run do not hold the session lock while they run. So request_cancel can stop an in-flight send from another thread. The CLI runs steps one after another, so this only matters for embedders.

One call is one process

Every postguy-cli call starts a new process with no workspace open. Any tool other than workspace_open fails with no workspace is open; call workspace_open first. For more than one step, use run --script. It runs a list of steps in one process and one session.

A script file cannot pass one step's result to the next step, because arguments are static JSON. Tools take ids, not names. For name-based flows, pick one of these:

  • Import something, then read the ids back with a list tool (import_text or import_file, then collection_list). Do this in a second run --script call, or read the printed result lines.
  • Let an agent read each step's output and generate the next script.
  • Use run --collection NAME --workspace DIR, which resolves names for you (see the CLI reference).

run --script step format

A script is a JSON array of steps, or an object with a steps array. Each step is {"tool": "<name>", "args": {...}}; args is optional. Steps run in order. The first step must be workspace_open, unless the tools you call need no workspace.

[
  {"tool": "workspace_open", "args": {"path": "work"}},
  {"tool": "collection_create", "args": {"name": "Smoke"}},
  {"tool": "collection_list", "args": {}}
]

Output is one line per step on stdout, {"step":0,"tool":"workspace_open","ok":true,"result":{...}}, then {"ok":true,"steps":3}. A failing step prints {"step":1,"tool":"...","ok":false,"error":"..."} on stderr, stops the run and exits 1.

This send flow fits in one script. The collection and request must already exist; use their real ids:

[
  {"tool": "workspace_open", "args": {"path": "work"}},
  {"tool": "request_send", "args": {"collection": "COLLECTION_ID", "request": "REQUEST_ID"}},
  {"tool": "response_get", "args": {}},
  {"tool": "history_list", "args": {"limit": 5}}
]

Tool reference

In the tables, an argument in bold is required. Safety is read-only (changes nothing), write, or destructive (deletes or clears data).

Workspace

ToolSafetyPurposeArguments
workspace_openwriteCreate the folder if needed and open it; takes the workspace lock. Paths stay inside --root when one is set.path — workspace folder
workspace_inforead-onlyPath, counts and the active environment id of the open workspace.none
workspace_export_zipwriteZip the workspace documents (not .postguy secrets/cookies/cache and not .trash); path resolves inside --root.out — zip file path
import_zipwriteReads .json entries (collection/environment/globals) from a zip through the normal importers; unsafe paths are refused, arbitrary entries are skipped.path — zip file path; replace (boolean) — replace same-id documents instead of suffixing

Collections and folders

ToolSafetyPurposeArguments
collection_listread-onlyCollections in sidebar order with id, name and counts.none
collection_getread-onlyThe full collection JSON.collection — collection id
collection_createwriteA new empty collection with a generated id.name — collection name
collection_renamewriteNew name; empty names are refused.collection — collection id; name — new name
collection_duplicatewriteDeep copy with fresh ids for every item.collection — collection id; name — name for the copy (default: <name> Copy)
collection_deletedestructiveMoves the collection file to the workspace trash and drops its secrets.collection — collection id
folder_createwriteInside the collection root or another folder.collection — collection id; parent — parent folder id (omit for the collection root); name — folder name
folder_renamewriteNew name; empty names are refused.collection — collection id; folder — folder id; name — new name
folder_deletedestructiveDeletes the folder and its contents; the subtree JSON is parked under .trash/item-<time>.json.collection — collection id; folder — folder id

Requests

ToolSafetyPurposeArguments
request_createwriteHTTP, gRPC or WebSocket; the protocol is fixed for the request's life.collection — collection id; folder — folder id (omit for the collection root); kind — http | grpc | websocket; name — request name (default New Request)
request_getread-onlyThe request JSON including its kind-specific body.collection — collection id; request — request id
request_updatewriteReplaces name, description and/or the kind-specific definition (the serialized RequestKind object).collection — collection id; request — request id; name — new name; description — new description; definition (object) — serialized RequestKind ({"type":"http",...})
request_movewriteInto a folder, or the collection root when folder is omitted.collection — collection id; request — request id; folder — target folder id (omit for the collection root)
request_duplicatewriteDeep copy into the same parent with fresh ids.collection — collection id; request — request id; name — name for the copy (default: <name> Copy)
request_deletedestructiveRemoves it from the collection; the JSON is parked under .trash/item-<time>.json.collection — collection id; request — request id
request_sendwriteRuns the full send pipeline (variables, inherited auth, cookies, proxy, redirects, decompression) and records History, Console and the response cache.collection — collection id; request — request id; environment — environment id (default: the workspace's active environment)
request_cancelwriteCancels the send started by request_send for that request id, or the most recent send (last), or a collection run (run:<collection id>).sendId — request id passed to request_send, last, or run:<collection id>
snippet_generateread-onlyOne HTTP request as cURL, raw HTTP, fetch, Python requests, Go, Rust reqwest, PowerShell or Node axios; variables stay unresolved. gRPC/WS snippets are not implemented yet.collection — collection id; request — request id; language — curl (default), raw-http, fetch, python, go, rust, powershell or node-axios; indent (integer, min 0) — spaces per level; 0 means a tab (default 2); include_boilerplate (boolean) — wrap the request in imports/main (default true)

gRPC, WebSocket and OAuth

ToolSafetyPurposeArguments
grpc_describeread-onlyLoads the request's service definition (proto set, inline files, or server reflection listing every service) and returns services, methods with streaming flags, and every reachable message's fields and types.collection — collection id; request — request id
grpc_example_messageread-onlyA default JSON object for the request method's input type.collection — collection id; request — request id
grpc_invokewriteCalls one unary method with JSON input (defaults to the request's stored message); returns the response JSON and metadata. Streaming methods use grpc_stream; grpc_send runs scripts and tests.collection — collection id; request — request id; message (object) — request message JSON (defaults to the stored message)
grpc_sendwriteInvokes a saved gRPC request through the full pipeline: pre-invoke script, variables, inherited auth as metadata, the call (unary or streaming, chosen from the method), on-message and post-response scripts and the Test tab. A non-OK gRPC status is a result, not an error.collection — collection id; request — request id; environment — environment id (default: the active environment)
grpc_check_messageread-onlyLists the JSON keys of a request message that the method's input type does not define, with their byte ranges. Defaults to the stored message.collection — collection id; request — request id; message — request message JSON text (default: the stored message)
grpc_set_protowriteCopies the .proto files (and the imports they pull in) into a workspace proto set, compiles it, and stores it as the request's service definition. Creates no collection. Paths resolve inside --root.collection — collection id; request — request id; paths (array) — the .proto files, together in one folder tree
grpc_streamwriteCalls a server-, client- or bidi-streaming method with an array of JSON messages and returns every response message in arrival order (cap 10,000). Unary methods use grpc_invoke.collection — collection id; request — request id; messages (array) — request messages in order (server streaming uses the first)
proto_importwriteCopies the .proto files (and the imports they pull in) into a workspace proto set under protos/<name>/, compiles it, and creates a collection with one gRPC request per service method (url {{grpcUrl}}). Compile errors name file:line:column. Paths resolve inside --root.paths (array) — the .proto files to import, together in one folder tree; name — proto set and collection name (default: the first file's name); replace (boolean) — move an existing set of the same name to the trash instead of suffixing the new one
ws_connectwriteConnects a saved WebSocket request (variables resolved at connect), returns a session id. Events are read with ws_messages.collection — collection id; request — request id
ws_sendwriteSend text or base64 binary to an open session; the echo/event log records it.session — session id; text — text message; binary_base64 — base64 binary message
ws_messagesread-onlyEvents after since (default 0) with sequence, direction, kind, text, bytes and close/detail; includes sent, received and network rows.session — session id; since (number) — last sequence number already read
ws_disconnectwriteSend a close frame and end the session.session — session id; code (number) — close code (default 1000); reason — close reason
oauth2_tokenwriteRuns client_credentials/password/authorization_code (with optional PKCE verifier) against the request's OAuth 2.0 auth, or refreshes it; stores the tokens in the secrets file and updates the request auth.collection — collection id; request — request id; mode — grant | refresh | code; code — authorization code for mode=code; verifier — PKCE verifier for mode=code with PKCE

Environments and globals

ToolSafetyPurposeArguments
env_listread-onlyId and name in order-file order, plus which one is active.none
env_createwriteAn empty environment with a generated id.name — environment name
env_renamewriteNew name; empty names are refused.environment — environment id; name — new name
env_duplicatewriteDeep copy with a fresh id; secret values copy too.environment — environment id; name — name for the copy
env_deletedestructiveTrashes the file, clears its secrets, and clears the active id when it pointed here.environment — environment id
env_set_activewriteenvironment: null clears it.environment — environment id or null
env_getread-onlyThe environment JSON with secret values rehydrated for the caller.environment — environment id
env_set_varwriteCreates the row or updates it; secret: true stores the value outside the environment file.environment — environment id; key — variable name; value — value (empty clears it); secret (boolean) — store the value in the secrets file; enabled (boolean) — row participates (default true); description — row description
env_unset_vardestructiveRemoves the row and its stored secret.environment — environment id; key — variable name
globals_getread-onlyThe globals file with secret values rehydrated.none
globals_set_varwriteCreates or updates one globals row (secret values split out).key — variable name; value — value (empty clears it); secret (boolean) — store the value in the secrets file; enabled (boolean) — row participates (default true); description — row description
variables_resolveread-onlyResolves {{variables}} and reports each hit's source scope, secret flag and unresolved state.text — template text; collection — collection id for collection variables; environment — environment id (default: active)
runtime_variableswriteThe runtime variables scripts set with pg.setVar/bru.setVar for a collection (session-lived, never saved). Returns them as an object; with clear they are dropped afterwards.collection — collection id; clear (boolean) — drop the variables after reading them

Import and export

ToolSafetyPurposeArguments
import_textwritePostman collection (v2.0/v2.1), environment or globals JSON, OpenAPI 3 / Swagger 2 (JSON or YAML), HAR 1.2, or cURL commands; auto-detected, name clashes get a suffix unless replace is set; returns the ImportReport.text — the JSON/YAML document or cURL command text; format — "auto" (default): the format is detected; replace (boolean) — replace a same-id collection/environment or the existing globals instead of suffixing/refusing; folders — OpenAPI folder layout: "tags" (default) or "paths"
import_filewriteSize-capped (100 MB) read, then the same mapping as import_text; the path resolves inside --root.path — file path; replace (boolean) — replace instead of suffixing; folders — OpenAPI folder layout: "tags" (default) or "paths"
import_brunowriteImports a Bruno collection folder (it must contain bruno.json): requests become a collection, environments/*.bru become environments (secret values go to the secrets store), and every other file (scripts, images) is copied into the collection's Assets keeping its relative path. Returns the collection, environments and assets outcome. The path resolves inside --root.path — the Bruno collection folder; replace (boolean) — replace instead of suffixing
export_collectionwritePostman v2.1 JSON or the Postguy native file; writes out or returns the JSON.collection — collection id; format — "postman" (default) or "native"; out — file path to write (inside --root)
export_environmentwritePostman environment shape; secret values are omitted unless include_secrets is set. Writes out or returns the JSON.environment — environment id; out — file path to write; include_secrets (boolean) — include secret values
export_globalswritePostman globals shape; secret values are omitted unless include_secrets is set. Writes out or returns the JSON.out — file path to write; include_secrets (boolean) — include secret values

Assets

ToolSafetyPurposeArguments
asset_listread-onlyThe files of a collection's Assets tab (path, size, modifiedMs), sorted by path. Scripts read them through pg.assets/require/fs, and bodies through {{% base64(file('path')) %}}.collection — collection id
asset_importwriteCopies files and folders (kept with their structure) into the collection's assets under dir; returns imported and skipped (with reasons). Name clashes get a (2) suffix unless replace is set. Paths resolve inside --root.collection — collection id; paths (array) — files and folders to import; dir — destination folder inside the assets (default: the root); replace (boolean) — overwrite same-named assets instead of suffixing
asset_deletedestructiveRemoves one asset file (a .bak copy stays beside it) and any folders left empty.collection — collection id; path — asset path, e.g. images/a.jpg
asset_renamewriteRenames an asset path; refuses when the target already exists. Returns the new AssetInfo.collection — collection id; from — current asset path; to — new asset path

Runner

ToolSafetyPurposeArguments
collection_runwriteRuns the collection (or one folder, or an ordered subset of requests) sequentially: scripts, tests, iterations and CSV/JSON data rows, delay, stop on error. gRPC and WebSocket requests are skipped. The result is stored (newest 20 per collection) and returned; cancel it with request_cancel run:<collection id>.collection — collection id; folder — folder id: run only this folder; environment — environment id (default: the workspace's active environment); iterations (integer, min 1) — iteration count (default: one per data row, or 1; at most 10000); delay_ms (integer, min 0) — pause between requests in ms (at most 600000); data — path of a CSV (header row) or JSON (array of objects) data file, inside --root; stop_on_error (boolean) — stop after the first request error, script failure or failed test; requests (array) — request ids to run, in this order (default: every request in tree order)
run_listread-onlyThe collection's stored runs, newest first, with totals and pass/fail.collection — collection id
run_getread-onlyThe full result of a stored run: iterations, requests, tests and failures.collection — collection id; run — run id from run_list
run_exportwriteRenders a stored run as json, junit (XML), html (one self-contained file), csv (requests table), xlsx (Summary, Requests and Tests sheets) or pdf and writes it to out (inside --root). Datetimes use the local time zone.collection — collection id; run — run id from run_list; format — json, junit, html, csv, xlsx or pdf; out — file path to write

Responses, cookies, history and console

ToolSafetyPurposeArguments
response_getread-onlyThe newest (or id) cached response: status, headers, body (base64 plus text when UTF-8, capped at 1 MiB), size and timings.id — history id (omit for the newest response)
response_savewriteWrites the DECODED body atomically to path inside --root.id — history id (omit for the newest response); path — file path
response_render_bodyread-onlyReturns the body as UTF-8 text (with replacement markers when invalid) or base64, capped at 1 MiB.id — history id (omit for the newest response); format — "text" (default) or "base64"
cookies_listread-onlyEvery jar cookie with domain, path, flags and expiry, plus the script allowlist.none
cookies_setwriteStores one raw Set-Cookie value for a URL (domain/path/secure/expiry rules apply) and persists the jar.url — the URL the cookie belongs to; setCookie — one Set-Cookie header value
cookies_deletedestructiveDeletes by (domain, path, name) and persists the jar.domain — cookie domain; path — cookie path; name — cookie name
cookies_cleardestructiveDeletes every cookie and persists the empty jar.none
history_listread-onlyThe newest sends, newest last (default 50).limit (integer, min 1)
history_openread-onlyOne entry by id, including the as-sent request snapshot.id — history id
history_cleardestructiveEmpties history.jsonl atomically.none
console_getread-onlyNewest-last console entries, optionally filtered by level or kind (default 100).limit (integer, min 1); level — "info" | "warning" | "error"; kind — "request" | "log" | "warning" | "error"
console_cleardestructiveDrops every retained console entry (the history file is untouched).none

Notes on some arguments:

  • ws_messages since and ws_disconnect code are declared as strings in the schema, but the implementation reads JSON numbers ("since": 12). A string value is ignored and the default is used.
  • env_set_active takes {"environment": null} to clear the active environment; the schema declares the argument as a string.
  • request_cancel takes the request id given to request_send, the word last, or run: followed by a collection id to cancel a collection_run.
  • snippet_generate languages: curl (default), raw-http, fetch, python, go, rust, powershell, node-axios. Variables stay unresolved in the output. See Code snippets.
  • collection_run with iterations omitted runs once per data row, or once without data. See Collection runner.

MCP server (planned)

There is no MCP server today. postguy-cli mcp is not a subcommand: the CLI prints its usage and exits with code 2. The feature is tracked as planned in Feature status.

The plan, from the project rules:

  • It is a stdio server started as postguy-cli mcp, over the same tool table as above.
  • It is opt-in: the app, the CLI and the installers never start it or register it with any client. The Windows installer explicitly registers no MCP server.
  • Any future network transport would be off by default, bound to loopback and token-authenticated.

Until it ships, an agent can run postguy-cli tools --json to learn the schemas, and postguy-cli call or run --script to run them.

Copyright © 2026