Coax documentation

Coax is a polished, file-based HTTP client. Your workspace is just a folder of .http files — edit them in the desktop app, then run the same files headlessly in CI with the CLI. This guide covers both.

Getting started

  1. Install & launch. Coax runs on macOS, Windows, and Linux. Get a license to download the app, then install and launch it.
  2. Open a workspace. On first launch, pick Open a workspace folder and choose any folder — Coax treats every .http file inside it as a collection. New to Coax? Choose Try with examples to start from a ready-made sample workspace.
  3. Open a request. Click any request in the sidebar; it opens in a new tab.
  4. Set variable values. If your file has @baseUrl = … lines, those become an environment that's activated automatically. Edit values on the request's Vars tab or from the Settings → environments manager.
  5. Send. Hit the green Send button. The response renders in the lower pane.

Workspaces

A workspace is a folder on disk — nothing more. The .http files inside it are the source of truth, so a workspace lives happily in a Git repo right next to the code it tests, and your teammates get the exact same requests when they clone.

  • Sub-folders inside the workspace become folders in the sidebar tree.
  • Environment files (*.env.json) sit next to the .http file they belong to.
  • Coax keeps a fast per-machine cache of the folder, but it never replaces your files — move or rename the folder and Coax just rebuilds the cache from the files on disk.

Open another workspace any time from the application menu; the active workspace is shown in the status bar.

Importing

Use the Import menu in the header. Coax can import from three sources:

SourceWhat you get
Import .http…A .http file (VS Code REST Client / JetBrains HTTP Client format) becomes a collection.
Import Swagger from URL…Point at a live OpenAPI/Swagger document URL; each operation becomes a request.
Import Swagger from file…Same, from a local OpenAPI/Swagger JSON or YAML file.

When importing a .http file, Coax:

  • Turns @var = value lines into an environment scoped to the new collection, and activates it so {{var}} references resolve immediately.
  • Creates one request per ### Title block, preserving headers and body verbatim.
  • Treats ############-style comment dividers as folder names.
  • Reads # @name foo as a request's chain name.

The sidebar is a single tree:

  • Collection — one .http file (folder icon).
  • Folder — a sub-grouping inside a collection.
  • Request — method + URL + headers + body + optional auth + chain name, shown with a colored method badge.

Right-click any collection, folder, or request for a context menu — add a new request, rename, or delete. Method badge colors: GET = blue, POST = green, PUT = orange, PATCH = purple, DELETE = red, HEAD = cyan, OPTIONS = indigo.

Editing a request

Open a request to edit it. The tab is organized into sub-tabs:

TabWhat it edits
Method & URLThe top row. Method dropdown (GET/POST/PUT/PATCH/DELETE/HEAD/OPTIONS) + URL. The URL supports {{var}} references, resolved at send time.
ParamsThe ?key=value query string, as a key/value editor that stays in sync with the URL.
HeadersRequest headers, same key/value editor.
BodyPick a kind — none, text, json, form, multipart, or graphql — and edit it in the Monaco editor with syntax highlighting.
AuthCapture credentials for None / Bearer / Basic / API Key. See the note below.
VarsShows the resolved value of every {{reference}} in the request, so you can confirm a value (or a chain) before sending.
cURLThe equivalent curl command for the request.

Edits autosave shortly after you stop typing — there's no Save button. Above the method row is an optional Chain name field; set it to make this request's response referenceable from others (see Response chaining).

Note on Auth: the Auth tab stores credentials with the request, but Coax does not yet auto-inject them into the outgoing request. For now, add an explicit header on the Headers tab — e.g. Authorization: Bearer {{token}}.

Variables & environments

  • A variable is a name → value mapping. Reference it anywhere with {{name}}.
  • An environment is a named bag of variables, scoped either global (visible everywhere) or to a specific collection.
  • One environment per scope is active at a time. Switch the active environment from the header dropdown; create and edit environments from Settings → environments.

Resolution order, highest precedence first:

  1. Request-local vars (@name = value inside the request)
  2. Active collection environment
  3. Active global environment
  4. Built-ins: {{$timestamp}}, {{$isoTimestamp}}, {{$guid}}, {{$randomInt min max}}

Secrets

Mark any variable as secret (in the environment manager, or via the lock icon on the Vars tab). Secret values are encrypted at rest using your operating system's secure storage and masked in the UI until you reveal them. When you export a collection, secrets are written as placeholders rather than real values, so the file is safe to share.

In CI the CLI can't read your machine's secure storage, so it reads each secret from an environment variable instead — see Environments & secrets below.

Response chaining

Thread one request's response into another:

  1. Set the source request's Chain name (e.g. getToken).
  2. Send it — the response is saved.
  3. Reference it elsewhere: {{getToken.response.body.$.access_token}}.

JSONPath is supported ($.field, $.items[0], $..nested). For a response header, use {{getToken.response.headers.x-request-id}} (header names lowercased). The Vars tab shows the resolved value so you can confirm a chain works before sending.

Sending & reading responses

Click Send. While in flight the button shows a spinner; click it again to cancel. When the response arrives you get a status pill colored by class (2xx green, 3xx blue, 4xx orange, 5xx / network error red) plus the time and size. Network, TLS, timeout, and invalid-URL failures render with a labeled error pill and the underlying message.

The response pane has three tabs:

  • Body — pretty-printed JSON / XML / HTML / text (read-only).
  • Headers — the response headers.
  • Raw — the full HTTP transcript: the request that was sent, then the response received.

Each open request is a tab in the strip at the top; tabs persist across restarts. Cycle the theme (light → dark → system) with the button, and drag the dividers to resize the sidebar and the request/response split — both are remembered.

Exporting

Click Export collection and choose where to save the .http file. Variable definitions are written as @name = value at the top; secret variables become placeholders instead of real values. If a request carries an Authorization header with a literal token (not a {{var}}), Coax warns you so you can scrub it before sharing. The result opens cleanly in VS Code REST Client and the JetBrains HTTP Client.

Where your data lives

Your workspace folder is the source of truth — the .http and *.env.json files you can see, edit, and commit. Coax also keeps a per-machine cache to make opening large workspaces fast:

macOS    ~/Library/Application Support/Coax/workspaces/<hash>/cache.sqlite
Windows  %APPDATA%\Coax\workspaces\<hash>\cache.sqlite
Linux    ~/.config/Coax/workspaces/<hash>/cache.sqlite

The cache is derived data — deleting it is safe; Coax rebuilds it from your files the next time you open the workspace. Secret values are never written to disk in the clear; they live in your OS secure storage.

Command-line (CLI)

Run the same .http files headlessly, with inline assertions — built for CI/CD, smoke tests, contract verification, and synthetic monitoring. The file your team edits in the desktop app is the file CI runs, unchanged.

Install & activate

The CLI is included with every Coax license. Install from npm (requires Node 18+):

npm install --global @melodicdev/coax-cli

Set your license key as an environment variable:

export COAX_LICENSE_KEY=COAX-XXXX-XXXX-XXXX-XXXX

In CI, store the key as a secret (GitHub Actions: secrets.COAX_LICENSE_KEY; GitLab: $COAX_LICENSE_KEY protected variable; etc.).

Usage & flags

coax run <file...> [options]
FlagDefaultPurpose
-e, --env <name>noneLoad vars from the *.env.json sibling whose name matches
-r, --request <title>noneOnly run requests whose title or # @name matches
-v, --var <key=value>noneOverride a variable; repeatable
-o, --output <reporter>prettypretty (terminal) or junit (XML for CI dashboards)
-t, --timeout <ms>30000Per-request timeout in milliseconds
-k, --insecureoffSkip TLS cert validation (for self-signed dev servers — like curl -k)
--fail-fastoffStop at the first failed request or assertion
--no-coloroffDisable ANSI colors (auto-disabled on non-TTY)

Exit codes

CodeMeaning
0All requests succeeded, all assertions passed
1At least one assertion failed
2At least one request failed (network, timeout, invalid URL)
3Parse error or CLI usage error
4License missing or invalid

Assertions

Inline assertions live above the request line, alongside # @name:

### Get user
# @name getUser
# @test status == 200
# @test $.user.email exists
# @test $.user.id == 42
# @test responseTime < 500
# @test headers.content-type contains "application/json"
GET https://api.example.test/users/42

Grammar: <left> <operator> [<right>]

Left sideMeaning
statusHTTP status code
responseTimeResponse time in milliseconds
headers.<name>Response header by name (case-insensitive)
$.path.to.valueJSONPath into the parsed JSON body
OperatorMeaningNotes
==EqualNumeric coercion: 200 == "200" is true
!=Not equal
< <= > >=Numeric comparisonFails cleanly if either side is non-numeric
containsString containsBoth sides must be strings
existsValue is present and non-nullNo right side

Right side: number, quoted string, true/false/null, bare string, or {{var}} reference (resolved before the assertion is parsed).

Environments & secrets

Drop *.env.json files next to your .http file and select one with --env <name> — the same format the desktop app uses, so a workspace round-trips between local editing and CI without changes.

my-workspace/
  api.http
  api.dev.env.json       ← { "name": "dev",     "vars": [...] }
  api.staging.env.json   ← { "name": "staging", "vars": [...] }
  api.prod.env.json      ← { "name": "prod",    "vars": [...] }
coax run api.http --env staging

Variable precedence (highest wins):

  1. --var key=value flags on the command line
  2. Vars from the --env <name> file
  3. @var = value declarations at the top of the .http file

Secrets in an env file ({ "key": "apiKey", "isSecret": true, … }) live in your OS secure storage when authored in the desktop. The CLI can't read that, so it looks for an environment variable named COAX_SECRET_<KEY> (the key uppercased):

export COAX_SECRET_APIKEY=sk_live_xxx
coax run api.http --env prod

A missing secret becomes a warning, not an error — the run continues with the non-secret vars available.

Response chaining

The CLI threads each response into the resolver, so chain references work end to end:

### Login
# @name login
POST {{baseUrl}}/login
Content-Type: application/json

{ "user": "rick" }

### Get my profile
# @test status == 200
GET {{baseUrl}}/users/{{login.response.body.$.userId}}
Authorization: Bearer {{login.response.body.$.token}}

Requests run in file order — put dependencies above their consumers.

CI integration

GitHub Actions:

jobs:
  smoke:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }

      - name: Install Coax CLI
        run: npm install --global @melodicdev/coax-cli

      - name: Run API smoke tests
        env:
          COAX_LICENSE_KEY: ${{ secrets.COAX_LICENSE_KEY }}
        run: coax run tests/smoke.http --output junit > coax-results.xml

      - name: Upload JUnit results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: coax-results
          path: coax-results.xml

Questions?

CLI package: @melodicdev/coax-cli. Email support@melodic.dev — or buy a license if you haven't yet.