Skip to content

POSTING 3 ~/guide/running/

Headless Runs

Overview

posting run sends saved requests without opening the terminal UI or connecting to a running Posting. Agents and scripts can use your existing requests, authentication and environments, then inspect the responses:

posting run api/health.posting.yaml --json
posting run api --env dev --json > results.json
jq -r '.results[0].response.body' results.json

It uses the same HTTP, GraphQL and gRPC clients as the UI, including authentication, TLS settings, uploads, request options and variable substitution. It doesn't open tabs, save history, or change the UI's environment. To send through a Posting someone is watching, use posting remote instead.

Working with agents

The bundled using-posting skill teaches agents both commands: use remote when Posting is open beside you, and run for saved requests when no instance is running or when you ask for headless execution. Installing the skill with posting remote skill doesn't require a running instance either.

Use --json so the agent gets response statuses, headers and bodies to work with. Error responses are included too: an exit code of 1 doesn't necessarily mean no response arrived. An agent can inspect a 404, for example, and decide whether it was expected for the task.

This is a request-execution command, not an assertion-based test runner. It can provide basic CI smoke checks, but doesn't verify that a successful response contains the right application data. Custom response assertions are outside its current scope.

Selecting requests

Give a .posting.yaml file to run one request, or a directory to run every request inside it, recursively. Hidden directories, node_modules and __pycache__ are skipped, just as in the UI. An empty collection is an error, rather than a successful run with no checks.

The collection root is the directory you give, or the parent directory of a single request file. Use --collection (-c) to select a different root. With -c, a relative request or subdirectory path is relative to that root; with no path, the whole collection runs:

posting run -c api users/get.posting.yaml
posting run -c api users
posting run -c api

Upload paths and gRPC schema paths are relative to the collection root, not each request's folder. Use -c when running a nested request that uses files from its parent collection.

Options may appear before or after the path. Unlike remote send, run takes file paths, not request display names, and the .posting.yaml extension is required for a single file.

Ordering and dependent requests

Requests run sequentially in case-sensitive lexical order of their relative file paths. This is different from the sidebar, which groups requests by method and display name. Use numbered filenames when order matters, for example:

01-login.posting.yaml
02-create-user.posting.yaml
03-get-user.posting.yaml
04-delete-user.posting.yaml

Cookies carry forward within the run, subject to each request's attach_cookies option. Response captures from successful requests become session variables for subsequent requests, taking precedence over environment and request-scoped values. Failed requests don't update captured values. Cookies and captures are discarded when the run ends.

By default, the runner continues after a failed request and reports every result. Use --fail-fast for dependent sequences so later requests aren't sent after a failure:

posting run api --env dev --fail-fast

Request files are loaded before any request is sent. Unreadable or malformed files, missing URLs, and references to legacy Python scripts abort the run. Posting 3 doesn't execute Python scripts, so run refuses them rather than silently skipping setup or assertions.

Environments

Without --env, the runner loads posting.env and posting.local.env from the collection root. It never uses the UI's remembered environment or implicitly loads environment files from the current working directory or Posting's config directory.

--env NAME (-e NAME) looks up a named environment in the collection root and applies the usual layers: posting.env, posting.local.env, NAME.env, NAME.local.env, skipping missing files. An explicit file path is relative to the current working directory and loads just that file. Repeat --env to layer names or files, with later values winning:

posting run api --env dev --env ./overrides.env

Use environment files to refer to secrets supplied by your shell, rather than putting credentials on the command line or committing them:

# api/dev.env
BASE_URL="${DEV_API_URL}"
API_TOKEN="${DEV_API_TOKEN}"

Posting's config.yaml and POSTING_* shell settings still apply, including custom CA bundles, client certificates and use_host_environment. With POSTING_USE_HOST_ENVIRONMENT=true, shell variables are available directly to requests, beneath environment-file values. Invalid settings abort the run instead of silently falling back to defaults. Settings aren't loaded from .env files.

Results and exit codes

Text output gives one line per request and a summary. It doesn't print response headers or bodies:

PASSED 01-health.posting.yaml: 200 OK (3.42 ms)
FAILED 02-users.posting.yaml: 503 Service Unavailable
1 passed, 1 failed, 0 skipped
Exit code Meaning
0 Every request passed.
1 A request failed, the run was interrupted, or its files/configuration couldn't be loaded.
2 Invalid command-line arguments.

HTTP 4xx/5xx responses, GraphQL responses with errors, non-OK gRPC statuses, transport errors, timeouts and failed response captures count as failures. Redirects aren't failures; requests follow them unless their follow_redirects option is disabled. Request timeouts also bound gRPC streams; there's no interactive stream mode in a headless run.

These are status checks, not custom assertions about your API's response. A 200 with the wrong application data still passes unless a declared capture fails. Inspect the JSON response to determine whether it meets the task's expectations. remote send keeps its different exit behavior: receiving any response is a success, even an error status.

--json prints one JSON document with results, passed, failed and skipped. Results are in execution order, each with file, name, outcome (passed or failed), an error on failure, and a response if one arrived. The response fields match remote send --json, including status, headers, trailers, elapsed time, and a textual body or bodyBase64 for non-UTF-8 data. Setup errors also appear in the report's top-level error field. Argument errors print usage diagnostics on stderr instead of a JSON report.

posting run api --env dev --json > results.json
jq '.results[] | {file, outcome, error, status: .response.status}' results.json
jq -r '.results[0].response.body' results.json

Reports may contain secrets

JSON reports contain response headers and bodies, which can include tokens, cookies or private data. Error messages can also include request URLs. Don't publish them as unrestricted artifacts or logs. Text output omits response bodies, but is not a secret-redaction mechanism.

Only run collections you trust, against an appropriate test environment: running a collection sends every selected request, including requests that modify data.