Coax CLI
Run .http files headlessly with inline assertions. Built for CI/CD, smoke tests,
contract verification, and synthetic monitoring. The same .http file your team
already edits in the desktop app.
Install
The CLI is included with every Coax license. Install from npm:
npm install --global @melodicdev/coax-cli
Requires Node 18+.
Activate
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.).
Quick start
Create a .http file with a request and one or more inline assertions:
### Healthcheck
# @test status == 200
# @test responseTime < 500
GET https://api.example.com/health
Run it:
coax run healthcheck.http
Usage
coax run <file...> [options]
| Flag | Default | Purpose |
|---|---|---|
-e, --env <name> | none | Load vars from <name>.env.json next to the .http file |
-r, --request <title> | none | Only run requests whose title or # @name matches |
-v, --var <key=value> | none | Override a variable; repeatable |
-o, --output <reporter> | pretty | pretty (terminal) or junit (XML for CI dashboards) |
-t, --timeout <ms> | 30000 | Per-request timeout in milliseconds |
-k, --insecure | off | Skip TLS cert validation (for self-signed dev servers — matches curl -k) |
--fail-fast | off | Stop at the first failed request or assertion |
--no-color | off | Disable ANSI colors (auto-disabled on non-TTY) |
Exit codes
| Code | Meaning |
|---|---|
0 | All requests succeeded, all assertions passed |
1 | At least one assertion failed |
2 | At least one request failed (network, timeout, invalid URL) |
3 | Parse error or CLI usage error |
4 | License missing or invalid |
Assertion syntax
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 side:
| Form | Meaning |
|---|---|
status | HTTP status code |
responseTime | Response time in milliseconds |
headers.<name> | Response header by name (case-insensitive) |
$.path.to.value | JSONPath into the parsed JSON body |
Operators:
| Op | Meaning | Notes |
|---|---|---|
== | Equal | Numeric coercion: 200 == "200" is true |
!= | Not equal | |
< <= > >= | Numeric comparison | Fails cleanly if either side is non-numeric |
contains | String contains | Both sides must be strings |
exists | Value is present and non-null | No right side |
Right side: number, quoted string, true/false/null, bare string, or {{var}} reference (resolved before the assertion is parsed).
Environment files
Drop *.env.json files next to your .http file and select one with
--env <name> — the same format the Coax desktop app uses, so a workspace
round-trips between local editing and CI without changes.
my-workspace/
api.http
dev.env.json ← { "name": "dev", "vars": [...] }
staging.env.json ← { "name": "staging", "vars": [...] }
prod.env.json ← { "name": "prod", "vars": [...] }
coax run api.http --env staging
Variable precedence (highest wins)
--var key=valueflags on the command line- Vars from the
--env <name>file @var = valuedeclarations at the top of the.httpfile
Secrets
Secrets in an env file ({ "key": "apiKey", "isSecret": true, ... }) live in
the OS keychain when authored in the desktop. The CLI can't read the keychain, so it looks
for an env var:
export COAX_SECRET_APIKEY=sk_live_xxx
coax run api.http --env prod
Missing secrets become warnings, not errors — the run continues with the unsecured vars available.
Response chaining
The CLI threads each response into the resolver context 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
Roadmap
- Block-form assertions (multi-line
@test { ... }) - JSON reporter with versioned schema
--chain <name>to run a named chain plus its dependencies- Desktop-paired license lookup (CLI reads desktop's license cache on same machine)
- Per-key CI activation flow (avoids burning the 3-machine activation limit on container rebuilds)
Source & support
Package: @melodicdev/coax-cli · Examples: github.com/MelodicDevelopment/coax · Email: rickhopkins@melodic.dev