Open source CLI and desktop app

Plain-text HTTP tests for humans, CI and AI agents.

Requests and asserts in .hurl files. Run them in Sonde Desktop, with sonde --test in CI, or through sonde mcp.

brew install nhtera/tap/sonde
Sonde Desktop running checkout.hurl: four requests pass, the fifth fails because the order status is pending instead of paid.The same run in the light theme.

One file. Three places it runs.

The desktop app, the CLI and the MCP server share one engine. A file that passes on your machine passes in CI and for your agent.

orders/checkout.hurl.hurl · Hurl 8
24▸POST {{base_url}}/orders25Authorization: Bearer {{token}}26Content-Type: application/json27{"cart_id": "{{cart_id}}"}28✓ passedHTTP 20129[Captures]30◆ capturedorder_id: jsonpath "$.order_id"3132▸GET {{base_url}}/orders/{{order_id}}33Authorization: Bearer {{token}}34✓ passedHTTP 20035[Asserts]36✕ failedjsonpath "$.status" == "paid"got "pending"37✓ passedjsonpath "$.total" == 25.8
Sonde Desktop run file local
4POST/orders → order_id201✓passed
5GET/orders/ord_1093 200✕failed
CI sonde --testGitHub Actions
error: Assert failure
  --> orders/checkout.hurl:36:0
   |
   | GET {{base_url}}/orders/{{order_id}}
   | ...
36 | jsonpath "$.status" == "paid"
   |   actual:   string <pending>
   |   expected: string <paid>

Failure orders/checkout.hurl (5 request(s) in 116 ms)
AI agent sonde_runsonde mcp --allow-run
// tool result
{ "filename": "orders/checkout.hurl",
  "success": false, "time": 116,
  "entries": [ … 5 entries, 1 failed assert … ] }

Calm surfaces. Loud results.

The interface stays quiet so the run can speak. Color appears only when it means something: a pass, a failure, a captured value, the method of a request.

checkout.hurlFailedlocal
8 passed1 failed116 ms12s ago
1POST/auth/login → token20029 ms✓passed
2POST/carts ← token→ cart_id20129 ms✓passed
3POST/carts/c_8f2a41/items 20020 ms✓passed
4POST/orders → order_id20110 ms✓passed
5GET/orders/ord_1093 ← order_id20028 ms✕failed

Assert failedline 36

jsonpath "$.status" == "paid"
Expected
"paid"
Actual
"pending"
✓L34HTTP 200
✓L37jsonpath "$.total" == 25.8

Everything an API test needs. In text.

Each feature is a few lines in a file you can review in a pull request.

Plain text, in git

Requests, captures and asserts live in .hurl files next to your code. Review them, diff them, blame them.

orders/checkout.hurl [Asserts] - jsonpath "$.status" == "created" + jsonpath "$.status" == "paid" + jsonpath "$.total" == 25.8
File format →

Environments and secrets

One sonde.yaml per project. Secrets stay in files git ignores and print as stars.

sonde.yaml →

OpenAPI contracts

Check every response against your spec and see which operations your tests cover.

OpenAPI guide →

Data-driven runs

Run a file once per row of a CSV or JSON file.

row 1 ada@example.com ✓ row 2 grace@example.com ✓ row 3 not-an-email ✕ 422
Data-driven guide →

Streams and gRPC

Server-Sent Events, WebSocket and gRPC calls in .sonde files.

event order.created 0.2s event order.paid 1.4s until matched · closed
Streaming guide →

Imports that write plain text

Bring requests from curl, .http files, OpenAPI specs and collection exports. Secrets are lifted into variables.

$ sonde import curl < login.sh POST {{base_url}}/auth/login Authorization: Bearer {{api_token}}
Import guide →

Your editor knows the format

sonde lsp brings diagnostics, completion and hover to VS Code, Neovim and any LSP client.

X-Client: {{na
name sonde.yaml · local
namespace capture · line 6
Editor setup →

Reports your pipeline already reads

One run, the formats CI dashboards and agents expect.

--report-json--report-junit--report-tap--report-html

Sonde Desktop. The same files, in a window.

A free app for macOS, Windows and Linux that reads your project folder. Nothing to sign in to.

Test run of the project's files with parallel jobs: passes and failures, with export to HTML, JSON, JUnit and TAP.Test run of the project's files with parallel jobs: passes and failures, with export to HTML, JSON, JUnit and TAP.
Download Sonde DesktopmacOS, Windows and Linux. Signed, with checksums.

Your requests stay yours.

No account

Open a folder and start. There is nothing to sign in to.

No telemetry

Sonde sends the requests you wrote. Nothing about you.

Local history

Runs are kept on your computer, with secrets redacted.

Your call on updates

The daily update check can be turned off.

Your first test in a minute.

  1. Install

    One binary from Homebrew, Scoop, Go, or a signed archive.

  2. Write a file

    A request, then the response you expect.

  3. Run it

    The same command on your laptop and in CI.

$ brew install nhtera/tap/sonde

$ cat health.hurl
GET https://api.example.com/health
HTTP 200

$ sonde --test health.hurl
Success health.hurl (1 request(s) in 41 ms)
--------------------------------------------------------
Executed files:    1
Executed requests: 1 (24.4/s)
Succeeded files:   1 (100.0%)
Failed files:      0 (0.0%)
Duration:          41 ms (0h:0m:0s:41ms)