Populars: Dades actualitzades el 27 d’octubre del 2026

Categories

Internet1.356
Comunicació321
Àudio i vídeo898
Gràfics i disseny539
Ofimàtica i productivitat1.124
Eines per a desenvolupadors3.134
Eines d’IA529
Seguretat i privadesa385
Eines del sistema3.114
Jocs523
Educació i ciència239
Xarxa i TI284

Vayu: baixar versions anteriors

Open-source API client with a native C++ load-testing engine - Postman-style requests and k6-level load tests in one local app.

Atharva Kusumbia API i desenvolupament web #91 API i desenvolupament web

Aquí hi ha 41 versions de Vayu, des de 29 de juliol del 2026 fins a l’actual, 0.45.0. Cadascuna enllaça amb els instal·ladors del mateix desenvolupador.

2026: 41 41 26
VersióDataMidaFitxers
0.45.0Darrera versió 22 d’octubre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.45.0 - 2026-10-22
Read before updating: this version upgrades the workspace database in a way
earlier versions refuse, changes which files a request may send from disk, and
makes a collection run carry on after a script error or a failed connection.
Vayu now sends a request-body file only when you picked it in Vayu on this
machine or it lies under a folder allowed in Settings > Files, and nothing else
can claim a file was chosen. New: the real uuid, lodash, moment,
csv-parse and xml2js libraries in scripts, Postman's legacy script globals,
and History charts that open quickly on a 24-hour run.
Added
- require() runs the libraries Postman scripts use. require('uuid'),
require('lodash') with the _ global, require('moment'),
require('csv-parse/lib/sync') and require('xml2js') with xml2Json run
the real npm libraries (#2650, #2651, #2652, #2653, #2654).
require('crypto-js') and the CryptoJS global cover the MD5, SHA-1 and
SHA-2 hashes, their HMACs and the Hex, Latin1, Utf8 and Base64 encoders
(#2578). Any other module, and any other CryptoJS member such as AES, still
throws and is named in the import notice.
- Postman's legacy script API runs (#2577): tests[...], postman.*,
responseBody, setTimeout and the other timers, and await at the top of
a script. These scripts used to throw at their first line.
- pm.environment, pm.globals and pm.collectionVariables accept a third
argument to set (#2664). set(name, value, { secret: true }) creates a
secret variable, and a type string ('string', 'number', 'boolean',
'json') sets the type. A secret is masked from the next run on, not inside
the run that created it.
- pm.variables.set, unset and clear write a run-local scope that is never
stored (#2564). pm.request.url.addQueryParams and removeQueryParams work
(#2662).
- Import tells you what will not run. The preview names the Postman
requests whose scripts use APIs Vayu does not run (#2576), and the notice
follows CryptoJS members reached through an alias or a destructure (#2628).
It also names the GET body Postman never sends, and the Data file picker has
Read numbers as numbers to match Newman's CSV reading (#2540). The
"file changed since this run" hint also notices a different number reading
(#2644).
- A Postman OAuth 2.0 collection keeps its audience, resource and other
token request parameters (#2536). The OAuth 2.0 token and refresh tables
choose per row whether it goes in the body, the query or a header (#2571).
- MCP agents can follow and steer a run. get_run reads a run's state, and
a running run's report is marked partial (#2436). run_request sends a saved
request by id when url is omitted (#2435). start_load_run states the
shape it runs (#2437) and sets which response samples get_run_samples
reads (#2447).
Changed
- The workspace database moves to schema version 7 (#2356, #2535). Once
0.45.0 opens a workspace, earlier versions refuse it, so going back to 0.44
means restoring a backup. The upgrade writes a copy of the database beside
it first.
- Data Safety Mode now defaults to Normal (#2419). The workspace database
used to run with Off, which can lose recent writes or corrupt the database
on a power cut or a crash. Installs that never changed the setting move to
Normal once, when 0.45.0 first opens the workspace; Settings > Data Safety
Mode sets it back to Off.
- A collection's folders and requests are numbered in one order (#2535).
The upgrade renumbers each collection's requests to follow its folders,
including folders in the trash, so every collection lists and runs exactly
as it did before. Like the rest of this upgrade it is one-way: an earlier
engine refuses the workspace afterwards. A new folder or request, or one
moved into a collection without a position, now goes after everything
already in it, folders and requests alike. A Postman collection imports in
the order Postman runs it: a request listed before or between folders stays
there in the sidebar, the import preview and a run, instead of every folder
moving above ev
0.44.0 17 d’octubre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.44.0 - 2026-10-17
Nothing to read before updating. This release makes load-test results easier to
trust and compare, adds Insomnia v5 import and Postman environment export, and
makes the first ten minutes smoother: a clearer welcome screen, curl paste, and
a fallback port when 9876 is taken.
Added
- Insomnia v5 import. Collections and environments exported as Insomnia v5
YAML import alongside the existing formats.
- Compare any two runs. A run in History can be compared with any other run
of the same request, with a warning when the two are not like for like, and a
p95, throughput and error-rate trend across a request's runs.
- A verdict on every load run. A finished run says whether it passed, on the
run itself and on its History row, and says so when the run was stopped.
Budgets carried over from a request are visible in the load-test dialogs and
tagged in the verdict.
- One report for a finished run. The dashboard shows History's report,
including the HDR plot, per-sample and slow-request views. The Samples tab
sorts by time, filters by status class, and error rows in the Overview link to
an example.
- Share a finished run. The new Export menu on a run, and the command
palette, save or copy it as Markdown (to paste into a PR or a chat), save
it as one self-contained HTML report with charts (to send to someone who
does not have Vayu), or save it as JSON. MCP agents get an export_run_report
tool that returns the report as Markdown or JSON. The same reports are available from
POST /export/run-report.
- Export an environment as a Postman environment from the environment row
menu.
- Vayu's own time per request. The response bar shows how much of a request's
time was Vayu's, not the server's.
- Import anywhere. Drop a file anywhere on the window to open the Import
dialog. Paste a curl command into the Import dialog or the URL bar to open it
as a request. The preview says which variables, auth and scripts came along,
and the import notes stay reachable inside the imported collection.
- A clearer first run. The welcome screen says what Vayu is for and offers
to connect a coding agent, and its New request tile works. If port 9876 is
taken, Vayu starts on another port and tells you which one to free.
- Load-test dialog. It names the target host and advises when it is not on
your network, shows a two-pane layout, and offers a collection load test the
same profiles as a request. "Virtual users" is the one name for the user
count. Fixed Iterations is now Fixed request count.
- MCP. The server runs on SDK v2 for both protocol eras.
- install.sh offers to open Vayu after a fresh install and refuses macOS
older than 13.3.
Changed
- The live error rate counts HTTP error responses, the same way every report and
MCP tool does.
- Runs are named Send, Collection run and Load test across History, the palette
and the welcome screen.
- The request and response tab strips fit the pane and move the rest into a
menu.
- An imported Postman environment is activated when none was.
Fixed
- Requests cancelled by Stop are counted apart from errors.
- A finished run no longer reports a lost live metrics stream.
- Scenario steps count HTTP error responses in their Errors tally, and replay
every enabled post-request script, never a disabled one.
- Sub-millisecond latencies print as such instead of "0 ms"; latency percentiles
and idle virtual users are no longer painted as failures; chart axes start at
zero and carry a unit.
- Counts and rates are grouped the same way on every run screen.
- A request rate below 10 req/s keeps a decimal instead of showing 0.
- The import loss report stays after a successful import.
- A root folder's badge counts its descendant requests.
- A file the OS hands Vayu opens in the Import dialog even when it is already
open.
- Internal: a vcpkg baseline bump (curl 8.23.0), documentation and comparison
pages brought back in line with the code, and test and refactoring work.
Every asset carries a build-provenance attestation: gh atte
0.43.0 14 d’octubre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.43.0 - 2026-10-14
Nothing to read before updating: this release adds a Start at login
setting, lets MCP agents read a GraphQL endpoint's schema, and remembers full
screen across launches.
Added
- Start at login. A new switch in Settings > General opens Vayu when you
sign in, on Windows, macOS and Linux. It shows what the system will
actually do, so turning Vayu off in Task Manager or System Settings turns
the switch off too. On Windows, Vayu also reopens if it was running when
Windows restarted to install updates.
- Agents can read a GraphQL schema. The new get_graphql_schema MCP tool
fetches a request's GraphQL schema the way a send would, with its
variables and auth, and only from hosts the agent is allowed to reach. A
Copy for agent button beside the operation picker copies a reference to
the selected operation.
Fixed
- A window closed in full screen reopens in full screen, not as an ordinary
window the size of the screen.
- Internal: the scripting engine's source split into smaller files, and
documentation kept in step with all of the above.
Every asset carries a build-provenance attestation: gh attestation verify <asset> --repo athrvk/vayu.
0.42.0 14 d’octubre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.42.0 - 2026-10-13
Read Changed before updating: element patterns now use a regular
expression dialect with no backreferences or lookaround. New: tabs can be
reordered, Copy for agent puts a reference to almost anything in the app
on the clipboard for an MCP agent, and a data-driven run records which file
drove it. This release also fixes several cases where a concurrent write,
a purge or an update lost data.
Added
- Reorder tabs. Drag a tab along the strip, or press Alt+Arrow, Alt+Home
or Alt+End on a focused tab. The palette can move the active tab left or
right.
- Copy for agent. Rows, tabs, detail headers and the palette can copy a
one-line reference that an MCP agent resolves with its tools: a request,
collection, environment, run, run comparison, inbox capture, mock server,
trash entry, example, variable, spec operation, run sample, element or
threshold. The reference names the item and never copies a value.
- MCP agents gain get_request, which reads one request by id, and
get_app_focus, which reports the open tab and the active environment.
- A data-driven run records its data file's name and a hash of its
contents. History shows Data: users.csv, adds (file changed since
this run) or (file no longer at that path) when that applies, and
the dashboard header shows the row count. The file's path is not stored.
- Element rows in a run show how long a timer waited and a transaction's
name.
- On macOS and Linux, Vayu appears in Open With for .json, .yaml and
.yml files, without becoming their default app. On macOS it also accepts
them dropped on its Dock icon.
- extract.json accepts keys with a hyphen ($.data.user-id), and every
element JSONPath field accepts bracketed names ($['a.b']).
Security
- With Write access off, run_request no longer saves what an agent's
extractors or scripts set to the globals, an environment or a collection.
They still run and report.
- With Reveal secrets to agents off, run output no longer shows the value
of a credential-named query parameter (api_key, for instance), and a
refused collection or scenario run no longer repeats the resolved URL to
the agent.
Changed
- Element patterns use RE2. A large response could crash the engine
through extract.regex, assert.contains, assert.jsonpath or a
control.if match, taking every run with it; patterns now run in linear
time on any body size. A pattern with a backreference or lookaround,
including one from a JMeter import, reports invalid regular expression
when it runs. (?i), (?s) and (?m) now work. See
Elements.
- Picking a file in the Data tab, Run collection or Load test
declares its columns as the collection's data contract, and Remove
clears it. Before, the old columns stayed until Re-declare.
- A send that fails without a response (a timeout or refused connection)
keeps the response tabs, so the request sent, its headers and its timings
stay readable.
- When the tab limit is reached, the tab you used least recently closes, not
the one opened first.
- Autosave no longer retries, every minute, a save the engine refused.
- Match system accent no longer overwrites the scheme you picked, which
returns when you turn it off.
- The engine API refuses malformed run and send settings (a null setting,
an out-of-range iteration count, rate, ramp or timeout, a non-string id,
an integer setting with trailing text, a monitor block on a collection
run) with an error naming the field.
Fixed
- Purging a trashed folder could delete a live folder that had been
created or moved into it. A trashed collection is now refused as a
parent, and a purge removes only trashed items.
- A send, stream or collection run could revert a variable written while
it ran by the app, an agent or another send. Only what the run itself
changed is saved now.
- On Windows, installing an update asked to close a running Vayu and then
force-closed it mid-shutdown, risking unsaved edits.
- Two transfers sharing a cookie scope no longer drop each other's cookies.
- Retention no longer deletes a run
0.41.0 9 d’octubre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.41.0 - 2026-10-08
Read Security and Changed before updating. MCP agents no longer
receive secret values unless you turn on Reveal secrets to agents, and an
agent can no longer send its own scripts while that setting is off. Secrets
are also withheld from recorded runs, exports, logs and several places in the
app that showed them in clear, and the workspace database moves to schema
version 5. New: History shows who started a run, and hovering any time shows
it in your zone and in UTC.
Added
- Hovering a time shows it in your time zone and in UTC, with how long
ago. This covers times in response bodies, headers, variables and the
editors, and Vayu's own times such as run start and end, cookie expiry and
History.
- History shows who started a run. A run an MCP agent started carries the
agent's name, a run with no saved request behind it is marked Unsaved,
and the list filters by origin (App or Agents).
- Save to request turns an agent's unsaved run into a saved request.
Security
- Agents no longer read secret values unless you allow it. A new
Reveal secrets to agents setting in Settings > MCP is off by default.
While it is off, secret variables, the credentials in auth blocks,
credential headers such as Authorization, cookie values, a password or
credential parameter in a saved URL and a proxy password reach an agent
marked as withheld, and a secret that appears in a run's output reads
<redacted>. Requests an agent sends still use the real values, and an
agent cannot clear a variable's secret flag to read it.
- An agent cannot change the proxy or the trusted certificate authorities
unless you turn on the new Network settings switch in Settings > MCP,
off by default and effective only alongside Write access.
- Recorded runs no longer store credentials. A typed Authorization
header, an API-key header and any secret variable value that reached the
URL, params, headers or body are withheld from the request a run records.
Runs recorded by earlier versions are not rewritten.
- Exports blank every credential they can recognise by name, not only
those inside auth blocks: credential headers and query parameters, example
requests, cookies and secret keys in imported auth settings. A header is
kept only when its whole value is one {{variable}}, so
Authorization: Bearer {{token}} is now blanked.
- On macOS and Linux the data directory and everything in it is readable by
your user only, including files an earlier version created. On Windows the
data directories are restricted to your account and administrators.
- Vayu no longer stores the full response an OAuth 2.0 provider returns,
which held refresh and ID tokens.
- A credentialed proxy URL no longer reaches the engine log however it is
written, and request debug logs withhold every credential header,
including the one an API-key auth names.
- The Resolved body view, the Σ peek on Params, Headers and form rows, and
the Params Sends line mask secret variable values, and the proxy URL
setting is a masked field.
- Code snippets mask credential headers by name, and catch a secret that
reached the URL percent-encoded.
- A hostile import file fails without harm: a deeply nested JMeter plan
imports what it can, an OpenAPI spec's $refs cannot read outside the
folder you picked or fetch from your machine, and an oversized import is
refused before it is read.
- A collection's scripts can no longer leave state behind for the next
script to read.
Changed
- The workspace database moves to schema version 5. Once 0.41.0 opens a
workspace, earlier versions refuse it, so going back to 0.40 means
restoring a backup. The upgrade writes a copy of the database beside it
first.
- With Reveal secrets to agents off, run_request and start_load_run
refuse scripts an agent supplies. A script sees every variable the
request resolves against, so it could copy a secret out. Stored scripts in
a collection still run.
- A masked credential header in a code snippet reads
Authorization: <secret>, without the scheme.
- The 
0.40.0 5 d’octubre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.40.0 - 2026-10-05
Read Security and Changed before updating. This version closes a
hole that let a web page open in your browser drive the engine, restricts
what a request may send and read on your machine, and upgrades the workspace
database again. It is also the first release that no longer migrates a data
directory left by 0.36 or earlier. The rest is hardening of the app window
and the release pipeline, and a handful of UI fixes.
Security
- A web page in your browser can no longer reach the engine. Vayu's local
API answered any website, so a page you visited while Vayu was running could
read every stored variable, including secrets, and change settings. The
engine now refuses browser requests outright; Vayu's own window is the only
one it serves. (GHSA-4mxh-5785-5q32)
- Only http and https URLs are sent, in a request, a run, a redirect
and pm.sendRequest. A file:/// URL used to return the file's contents
as the response.
- A file a request names is sent only if you chose it in this app or it lies
under a folder you allowed. Earlier versions could be told the file was
chosen by whoever wrote the collection.
- Settings > Files refuses /, a drive root, your home folder and any
folder that contains it. An existing entry of that kind is removed on
upgrade and the engine log says which.
- The HTML Preview runs no script and loads nothing from the network. A
page that drew its styles or images from a CDN now renders plain. Links in
it stay inert, and the "links are disabled" tooltip is gone.
- The app window carries a Content Security Policy and refuses every device
permission request, and the chart tooltip renders metric names as text.
- Release installers are built with provenance attestations, every GitHub
Actions step is pinned to a commit, and install.sh verifies what it
downloads and stops if it cannot.
Changed
- The workspace database moves to schema version 4. Once 0.40.0 opens a
workspace, earlier versions refuse it, so going back to 0.39 means restoring
a backup. The upgrade writes a copy of the database beside it first.
- The data directory is no longer migrated from vayu-client. 0.37
through 0.39 renamed the directory left by 0.36 and earlier. Upgrading from
0.36 or earlier straight to this version starts with an empty workspace;
install any 0.37 to 0.39 release first, or rename vayu-client to Vayu
in your app data directory yourself.
- A request that cannot be sent because of its URL reports Couldn't send to
this URL and names the reason.
Fixed
- Typing in the Params table re-rendered every row on each keystroke.
- Holding a keyboard shortcut to resize a pane saved the layout on every key
repeat.
- The dashboard header redrew on every metrics tick.
- Menus, dialogs and the markdown editor reserved a dead strip on their right
edge for a scrollbar that never appears there.
- A few icon buttons and compact controls were smaller than every other
control; they match now.
- The macOS update command Vayu prints matches the documented one.
- Internal: documentation kept in step with all of the above, and the
repository gained role definitions for the agents that help maintain it.
Every asset carries a build-provenance attestation: gh attestation verify <asset> --repo athrvk/vayu.
0.39.0 1 d’octubre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.39.0 - 2026-10-01
Read Changed before updating: this version upgrades the workspace
database again, and an imported form-data file is no longer sent until you
choose it or allow its folder. The headline changes are a Binary file
body mode, a new Settings > Files page that decides which files a request
may send, and URLs and query strings encoded the way Postman sends them,
including hosts with non-ASCII names.
Added
- Binary file bodies. The Body tab has a Binary file mode that sends
one file as the whole request body. Choose it, drop it on the editor, or
type a path; a path can use variables, such as {{fixturesDir}}/avatar.png.
Files of any size are supported, and large ones are streamed from disk.
- The body's Content-Type comes from an enabled Content-Type header if you
set one, else the type you pick in the editor, else the file extension,
else application/octet-stream. Code snippets show the same type.
- Settings > Files. Vayu sends a file you chose in the editor, or any file
under a folder you allow on this page. A path that came from an import, a
pasted curl command, an AI agent, a data file or a variable is sent only from
an allowed folder, so an imported collection cannot read a file you did not
pick.
- A request with a file nobody chose here shows Not chosen on this machine
with Relink and Allow folder.... The import preview lists the folders
an import's files live in, each with Allow folder.
- Binary bodies import from Postman (mode: "file"), Insomnia, OpenAPI
(application/octet-stream and format: binary) and a pasted
curl --data-binary @file or wget --post-file, and the Postman and OpenAPI
exports and code snippets write them back. Before this version they were
dropped with a count.
- History shows each sent file's name, size and SHA-256. The path and the
contents are not stored.
- AI agents can add a file to a request, but Vayu sends it only after you
choose it or allow its folder.
- A request to a host with a non-ASCII name, such as bücher.example, is sent
using its punycode name, as Postman does. Client certificates and proxy
rules written with either spelling apply to it.
Changed
- The workspace database moves to schema version 3. Once 0.39.0 opens a
workspace, earlier versions refuse it, so going back to 0.38 means restoring
a backup.
- An imported form-data file is no longer sent until you relink it or allow
its folder. Earlier versions tried to send it from the path in the
collection, which usually failed on another machine.
- A missing, unreadable or untrusted file stops the send or run with a message
naming the file and what to do. A collection or load run checks every file
before it starts.
- URLs, query values and query-placed credentials are encoded the way Postman
encodes them, including in pm.sendRequest and values filled in only at
send time. An imported query row with an empty value is sent as key=, a
row with no value at all as key.
Fixed
- A load or collection run against a host that resolves to more than one
address (*.localhost, for instance) could fail where Send worked.
- The Params table lost a query row's valueless state, and editing one row
re-encoded the others.
- A {{variable}} in the query was shown on the Sends line differently
from how it was sent.
- Internal: documentation kept in step with all of the above.
0.38.0 1 d’octubre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.38.0 - 2026-10-01
Read Changed before updating: this version upgrades the workspace
database, and earlier versions cannot open it afterwards. The headline changes
are a Postman Collection export, path variables (:id in a URL) with their own
table, and Postman's per-request protocol settings. The Linux AppImage and
.deb start again on Ubuntu 22.04 and Debian 12.
Added
- Export to Postman. Export as Postman Collection in the Spec tab and
the collection tree menu writes a Postman v2.1 collection file. Auth secrets
and secret variables are left blank unless you choose to include them. An
imported collection exports close to how it came in: saved responses,
variable types and descriptions, header types, scripts (in order, with
disabled ones kept off), and the original auth block are written back. The
MCP server has a matching export_postman tool.
- Path variables. A :name segment in the URL gets a row in a new Path
variables table on the Params tab, and the value is sent in its place.
Values are encoded the way Postman encodes them. Postman and Insomnia path
variables import into the table, and the table carries over into code
snippets and the Postman and OpenAPI exports.
- Save as example keeps the request as it was when you clicked Send, so
the Postman export writes the request that actually produced the response.
- Postman's protocol settings, per request. The request's Settings tab
has Disable cookie jar, Send URL without encoding, and a Don't
send automatic headers list (User-Agent, Accept, Accept-Encoding,
Content-Type, the correlation id). Postman's disableCookies, disableUrlEncoding and
disabledSystemHeaders import into them and export back.
- Postman Hawk, OAuth 1, EdgeGrid and JWT auth are kept on import, so they
export back. Vayu does not sign requests with them, and the import preview
says so, including when the auth is set on a collection or folder.
Changed
- The workspace database moves to schema version 2. Once 0.38.0 opens a
workspace, earlier versions refuse it, so going back to 0.37 means restoring
a backup.
- The Linux build needs glibc 2.35 or later: Ubuntu 22.04, Linux Mint 21,
Debian 12, Fedora 36 or newer.
Fixed
- The Linux AppImage and .deb failed to start on Ubuntu 22.04, Linux Mint
21 and Debian 12 (GLIBC_2.38 not found), so the app opened without an
engine.
- A saved light or dark theme was ignored at launch and the app followed the
system theme.
- At launch, the collection tree, the Launcher and a restored request tab
could show "Couldn't reach Vayu's engine" while the engine was still
starting.
- Editing an imported request's or collection's auth left the old imported
credentials stored beside the new ones.
- An export without secrets still wrote the client secret, refresh token and
PKCE code verifier nested in an imported OAuth 2.0 block.
- Editing an imported collection variable dropped its description.
- Replaying a design run whose path value was still a {{variable}} sent
/users/:id literally, and Save to request cleared the row.
- Internal: a much faster pre-commit lint for engine test files, dependency
updates, and documentation kept in step with all of the above.
0.37.0 25 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.37.0 - 2026-09-25
App launch and engine shutdown are substantially faster, especially on large
workspaces, and MCP gained four tools for connection diagnostics, client
certificates, and import/bind previews. Also here: a fix for a dropped-cookie
import notice, a Windows database-reclaim bug, and app data now living under
a clearly named folder.
Added
- MCP gained four tools: diagnose_connection (says which hop actually
failed - proxy, CA, or client certificate - instead of just reporting the
API as down), list_client_certificates, and read-only previews for
import and OpenAPI binds (preview_import, preview_spec_bind) that
answer the same question the real action would, without applying it.
- MCP's collection tools and resource now include a linked data file's path
and name, and the columns it declares, so an agent can build data rows and
open the file directly.
Changed
- App launch and engine shutdown are substantially faster, especially on
large workspaces. On a 300-collection workspace, the launch burst that used
to take about 7 seconds now completes almost instantly, and quitting the
engine dropped from roughly 300ms to about 10ms.
- The deprecated /request, /run/*, /metrics/live/:id and /stats/:id
routes are removed; use /execute, /runs, and /runs/:id/live instead.
GET /runs with no query parameters now always returns the paginated
envelope.
Fixed
- Importing a request with a cookie parameter told you to add it to the
cookie jar, which nothing in the app does from there; it now points you at
adding a Cookie header instead.
- App data now lives under Vayu instead of the npm package's old name,
vayu-client; an existing install is migrated automatically on first
launch.
- On Windows, a heavily-pruned database could fail to reclaim its freed disk
space at startup.
0.36.0 24 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.36.0 - 2026-09-24
Hovering a {{variable}} token now opens its real popover instead of a
separate read-only tooltip, and a collection's export/import round trip
carries every field now instead of losing most of what the UI shows. Also
here: deleting from the collection tree with no confirm dialog, several
layout fixes at the app's default density, and the macOS menu bar's own
name.
Added
- Hovering a {{variable}} token now opens the same popover a click does,
after the usual debounce, instead of a separate read-only tooltip. A click
on the token itself now only places a text caret in it - editing the raw
token text no longer needs arrowing in from an edge.
- Deleting a collection or request from the tree runs immediately, with no
confirm dialog - it was already an undoable soft delete, so the dialog was
guarding a mistake Undo already covers. A collection with a mock server
running still asks, since stopping that mock isn't something Undo brings
back.
- Exporting a bound collection now asks whether to Keep contract
(examples and parameter values only, the existing default) or
Write everything, which writes every field - names, auth, scripts,
saved examples, even new operations - back into the document's own
dialect, Swagger 2.0 included. Importing an OpenAPI, Postman or Insomnia
file now keeps folder nesting and descriptions, collection variables,
execution settings, GraphQL bodies, digest/AWS/NTLM auth and more that
used to silently drop on the way in or out.
- An import preview that skips a request now names it, instead of only
saying how many were skipped.
Changed
- Error messages, dialog copy and labels throughout the app were rewritten
against a new writing guide: "can't" instead of "cannot", one settled
term per concept (like "Vayu's engine" for the sidecar), and plainer
language in place of jargon and dropped metaphors.
- Settings' backup card is now just called Backup - "Workspace" isn't a
Vayu concept.
Fixed
- Toasts, the Trash drawer's item names and Settings' header text could
crowd against the buttons next to them at the app's default density -
several places were sized off the density setting itself rather than a
fixed measure, up to 25% narrower than the class name implied. The same
gap is fixed everywhere else it turned up: menus, popovers, autocomplete
lists, dropdown floors and skeleton placeholders.
- Hovering one variable and then quickly hovering a different one in
another editor could close the second popover instead of the first - a
stale timer from the first was closing whatever was open rather than the
one it was actually scheduled for.
- The popover for a {{token}} in a script or body editor could close
itself while the pointer was still resting on it, unless you'd clicked
inside first.
- The popover for a {{token}} in a header field or the URL bar could
flicker instead of opening.
- The macOS menu bar read "Quit vayu-client" instead of "Quit Vayu".
- A DNS failure and a target server breaking the connection (an empty
reply, a reset, a redirect loop) were both reported as generic
connection or internal errors instead of naming what actually happened.
- Importing an OpenAPI file from a URL that answered with an error page (a
404 or 500) blamed the file's format instead of naming the server's
answer.
- A second delete queued behind one still running could be silently
dropped, and a failed create, duplicate or delete could leave the Dock
reading "Not saved" as if an edit were still pending.
- Introspection reported "HTTP 0" as if the endpoint had actually answered,
instead of naming why nothing came back.
0.35.2 22 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.35.2 - 2026-09-22
A patch release. The one to update for: a data-driven single send could go
out with a template token still in it instead of the row's value. Also here:
a double-click on Get Token that could throw away the OAuth token it had just
fetched, two Settings buttons that widened while they worked, and a caret
shorter than its neighbors.
Changed
- Re-sending a request now sweeps a faint band across the dimmed response
pane while the new one is on its way, instead of a plain, motionless dim -
the previous response underneath stays just as readable.
Fixed
- A single send with a bound data row could send a request with the wrong
value - or none at all. The row picker beside Send, and a single
request's own load test, only filled in a token spelled {{data.column}};
a column referenced the plain way, {{column}}, reached the server exactly
as written instead of that row's value. A collection run was never
affected. If a request or its auth used the bare spelling, re-check what it
actually sent before this fix - it was accepted by the server as literal
template text rather than refused.
- A second click after fetching an OAuth token could delete it. Clear sat
to the right of Get Token, and a token landing slid the button left by
Clear's width - a normal double-click on the same spot hit Clear instead
and threw away the token that had just arrived. The buttons no longer move
once a token lands.
- In Settings, the Connection test card's Test button and the Add certificate
button both widened while their request was in flight, shrinking the URL
field beside Test and sliding Cancel sideways. Both now hold their size and
swap an icon in place instead.
- The form-data row's text/file switch now crossfades between its two icons
instead of swapping them in a hard cut under the pointer that just clicked
it.
- The launcher and first-run screens now fade in like every other screen in
that spot, instead of popping in with a hard cut.
- The row-picker caret between Send and Load Test - shown once a collection's
CSV or JSON data file is bound - was a few pixels shorter than the buttons
on either side of it.
0.35.1 22 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.35.1 - 2026-09-22
A patch release: a resize flash on the script editor, a cut-off suggestion
list, and a value like {{$randomInt}} changing on screen without you
touching anything.
Changed
- The Bulk edit / Table toggle above Params and Headers is now a smaller
segmented control, matching the compact controls used elsewhere in the app.
Fixed
- A dynamic value could change on screen with nothing edited.
{{$randomInt}}, {{$guid}} and the like generate a fresh value each time
they're read, and three places re-read them on almost every redraw instead
of once: the Params tab's resolved-URL preview, a GraphQL request's schema
lookup, and an unnamed tab's own title. All three now hold the value they
first showed until something about the request actually changes.
- Dragging the script editor's height no longer flashes back to the old
height right after you let go. The same drag, and the drawer/context-bar
width drag, now also take Page Up/Down, Home, End and a reset key, and
releasing the pointer outside the window no longer leaves the drag stuck.
- The Headers tab's key suggestion list was cut off after 10 entries with no
way to reach the rest of the 31 standard headers; it now scrolls to every
entry.
- Switching Params or Headers into Bulk edit hid the "Added by Vayu" default
headers and the resolved-URL preview; both now stay visible, and a Discard
button lets you leave Bulk edit without applying a half-finished draft.
- The "Open Demo API" tile now also appears on a brand-new, empty workspace's
welcome screen, not only after you've already created a collection or
request.
- The workspace-backup restore instructions now say the copied file also
needs renaming to match the live database - following them literally used
to leave two files side by side instead of replacing anything.
0.35.0 21 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.35.0 - 2026-09-21
A Demo API tile for a first run with an empty workspace, plus fixes to the
Import dialog's tab strip, a Monaco editing bug in variable popovers, and the
scripting docs for pm.request.body.
Added
- The Launcher now shows a Demo API tile below its action grid while your
workspace has no runs yet. It sends a real request against a public demo
endpoint, so there's something to see execute before you write your own -
it goes away once you've run anything.
Fixed
- Editing a variable in a token's popover and pressing Enter to commit could
split the line underneath it in the editor instead, because focus returned
to the editor before Enter's own newline action landed.
- The Import dialog's File/URL/Paste tabs rendered at the smaller size meant
for a tab strip nested inside a section, not a dialog's own top-level
navigation.
- The scripting docs and completions for pm.request.body didn't say that
assigning it directly (pm.request.body = ...) replaces the whole object -
a later pm.request.body.raw read in the same script then returned
undefined instead of the string just set.
0.33.0 20 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.33.0 - 2026-09-20
The icons move now, and the app's interactions were audited end to end for
consistency. Every glyph on a button, a menu item, a tab, a settings category
or the activity rail has a motion of its own on hover, in the style of an
animated icon set, with no new dependency and full respect for the reduced
motion setting. Beyond that: a greyed-out control tells you why it is off,
breadcrumbs on the detail tabs, a confirm before clearing an inbox, Move up
and Move down in the collection tree, and a long list of small places where
the same action was done two ways and now is done one.
Added
- Icons that move. Hover or focus a control and its icon acts out what it
is: the trash lid lifts, the clock's hands turn, the radio's waves travel
outward, the folder tilts open, the braces part, the search lens wiggles, the
download arrow drops into its tray, the pin leans, the bell rings, the gauge
needle sweeps. All 26 motions run from the button or row that owns the icon,
never from the icon itself, and none of them loop. A status icon that is
reporting a state stays still. The reduced motion setting, and the operating
system's own reduced motion preference, collapse every one of them.
- State changes crossfade instead of popping: Copy to a check, Show to
Hide on a secret, Play to Stop, a folder opening and closing.
- A disabled control says why. Hover a greyed-out button and the reason is
there: "No captures to clear", "No unsaved changes", "Already first" on a
menu item that cannot move further.
- Breadcrumbs on the detail tabs. The collection tab, the dashboard and a
run's report show where they live, with each ancestor clickable. A nested
collection shows its chain; a root collection shows nothing extra.
- Move up and Move down in a collection tree row's menu, beside the
existing drag.
- Empty trash in the Trash panel's header.
- Empty states offer the way forward. An empty dashboard, history list,
services list, mock server, console or request pane carries the button that
fills it, rather than a sentence pointing at a toolbar.
- Clearing an inbox's captures asks first, naming how many it is about to
remove. It was the one destructive action in the app that did not.
- Run status in the history sidebar carries a shape as well as a colour, so a
finished, failed and stopped run are distinguishable without colour vision.
- Import progress is announced to assistive technology as each step completes.
Changed
- Copying shows a check on the button it came from. A copy from a menu
item or a text button toasts, naming what was copied. A copy that the system
refused now says so in both cases; it used to fail silently.
- Delete confirmations read the same way everywhere: the item by name,
and "and everything inside it" when children go with it, where they used to
be worded per screen.
- A new folder is called New Folder, not New Sub Collection.
- Services rows show their actions on hover, like every other row.
- A history row whose URL does not fit keeps the path and drops the host,
since the path is what tells two runs apart.
- The welcome screen sits in a centred reading column instead of stretching
to the window's width.
- The settings restart banner and the dashboard's slow-request notice read as
warnings, not errors.
- Consistency pass across the app: one look for tab strips and pane headers,
one component each for field, block and pane errors, one section-label
style, one Cancel button, named sizes for the two smallest type steps and
the small icon size, and one hover treatment for row actions. No behaviour
changes beyond those listed above.
Fixed
- Renaming a collection, folder or request commits only on a plain Enter.
An Enter that finishes composing a character in an input method, or an
Enter carrying Ctrl or Cmd, no longer commits a half-typed name. Escape
always cancels; it used to commit in two of the trees.
- The spare row at the bottom of a params, headers or variables table no
longer shows an enable checkbox for an e
0.32.1 18 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.32.1 - 2026-09-17
Density no longer shrinks things that need a floor of their own, and a few
layout glitches that came with fixing it are cleaned up too. Read this before
updating if you use anything other than Default density.
Fixed
- The tab strip, drawer header, response toolbar, and update/recovery banners hold a fixed height at every density instead of shrinking as low as 24px at Default.
- Every interactive control now clears the 24x24px touch-target minimum at every density - switches, checkboxes, toasts, dialog and tab close buttons, the history sidebar's pin/delete buttons, and icon-only buttons throughout collections and the Elements tab no longer shrink as low as 21px, 15px, 12px or smaller.
- Icons hold a fixed 16px (or 12px for compact icons) floor instead of shrinking to 9px at Default density.
- The response body's Pretty/Raw switch spilled past the bottom of its toolbar, and the Elements tab's enable switch touched the top and bottom of its row - both now sit with room around them.
- A segmented control (the load test dialog's Response format, and the client certificate form's Format) rendered beside its label instead of under it.
- Text fields held their value closer to the border than the rest of the app's controls.
- The enable checkbox in the request/response key-value rows and the variables tables rendered as a barely-rounded flat square instead of the app's rounded, accent-coloured control - both now share one properly styled checkbox.
- Validation messages across the app now speak in plain language instead of echoing an internal identifier, a raw wire key or a 0-based array index: element and load-run step errors name the item by its label and position (e.g. "Throughput" or "'Assert status code' (item 2)"), Settings and the load test dialog's budgets name the field the way its own control does ("Worker Threads", "p99 latency"), a mock server that can't be found says so in plain English, and a schema-mismatch error ("must be a number", "must be one of [...]") is rebuilt from the schema's own declared title and bounds instead of quoting the validator's internal wording.
- The variable popover's value field was too narrow for anything longer than a short value (a URL, a domain), scrolling inside the box rather than showing it. It's wider now, capped so it still fits inside a small window.
- Checkboxes outside the request/response key-value rows and the variables table were still the browser's bare, unstyled control - the default-headers list, the OpenAPI sync dialog, and the import dialog's toggles. They now share the same styled checkbox, and its checkmark is sized to the box (rather than fixed to one icon step) so it no longer fills a small box edge to edge or overflows a large one.
- A checkbox's corner radius stayed a fixed size while the box itself didn't, so the same setting made a small checkbox (a default-header toggle) read as a circle - indistinguishable from a radio button - while a large one (a key-value row's enable checkbox) stayed a normal rounded square. The radius now scales with the box, so Square still turns every checkbox fully square and Rounded no longer turns a small one into a circle.
Changed
- The load test dialog's Comment field moved to the top, above Load profile, so a run can be named before it starts instead of found later behind Recording & limits.
- The load test dialog's Scripts control moved after the load profile summary, since that summary is still describing the profile fields directly above it and Scripts is the first control that isn't about the profile.
0.32.0 17 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.32.0 - 2026-09-17
Settings panels stop leading with a wall of text.
Changed
- A setting description longer than about two lines is now collapsed behind a Show more toggle, so the control it explains is visible without scrolling past it. This covers Settings > AI agents (MCP) - the card, category and per-tool descriptions - and every engine settings category. Shorter descriptions are shown in full as before.
0.31.0 17 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.31.0 - 2026-09-16
Settings gains a Density control, and two import formats keep more of what they're given.
Added
- A Density setting in Settings > Appearance > Interface. Default is noticeably tighter than before - about a third more rows fit in the same window - and Comfortable keeps the previous, roomier spacing for anyone who prefers it.
Fixed
- Postman import now creates a client certificate entry (Settings > Network > Client Certificates) from a request-level certificate, when it points at a file Vayu can read, instead of only reporting it as skipped.
- JMeter import now reads a "Files Upload" sampler into a form-data body with its file fields, instead of dropping it.
0.30.0 15 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.30.0 - 2026-09-15
This release improves constant-RPS load-test pacing accuracy on Linux and macOS.
Changed
- Linux and macOS: constant-RPS load runs are more evenly paced at low-to-moderate rates. Load-generation threads previously slept with no correction for wakeup overshoot, so a tick could land late and the next one paid it back as a doubled dispatch - the same effect Windows already had fixed. Pacing now uses each OS's precise timer, and worker threads are pinned to their own CPU core when the configured worker count leaves one spare.
- Internal: the Windows engine build fixed a macro-name collision with two of libcurl's Windows headers.
0.29.2 14 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.29.2 - 2026-09-14
Vayu's accent color can now follow your operating system's own accent color on Windows and macOS. Also in this release: two more import fixes, found while auditing the JMeter response-assertion and path-variable logic landed in 0.29.1, and two fixes to Windows auto-updates.
Added
- A "Match system accent color" toggle in Settings > Appearance. Turn it on and Vayu switches to whichever of its accent color schemes is closest to your OS accent color, and follows it live if you change it in system settings. Off by default, and not shown on Linux, which has no system accent color to read.
- The update banner now shows a progress bar while an update downloads in the background, instead of going quiet between "update found" and "restart to install."
Fixed
- A JMeter response assertion with "Not" ticked now imports as its own negation, not its opposite. A check that a response does not contain a given text used to import as checking that it does, so a plan that passed every request in JMeter failed every one in Vayu.
- A JMeter response assertion's Contains and Matches pattern types now import as a regular-expression match rather than a plain text search, and one set to match any of several patterns is flagged in the import summary instead of silently requiring all of them.
- A colon inside a URL's query string is no longer mistaken for a path variable. An Insomnia request whose query string contained something like color:id used to have :id replaced with the path variable's value even though no path parameter named id appeared in the path itself.
- A URL with the same path variable appearing more than once now has every occurrence substituted, not just the first.
- A Windows update or uninstall no longer hangs on a prompt nobody can see. Two installer dialogs - closing a running Vayu, keeping saved data - showed up even during an unattended update (winget, or Vayu updating itself) and blocked it indefinitely with no way to answer. Both now proceed with the safe default instead of asking.
0.29.1 13 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.29.1 - 2026-09-13
A round of import fixes across every supported format, found by testing the importer against real-world OpenAPI, Postman, Insomnia and JMeter files and auditing it field by field against each format's own specification.
Fixed
- A disabled element in a JMeter plan now stays disabled on import. A sampler, controller or assertion turned off in JMeter's own UI used to import as active anyway, with no way to turn it back off.
- Insomnia path parameters now resolve correctly. A URL using Insomnia's :name path-parameter syntax used to import with the literal :name still in it, so the request failed on first send.
- An explicit "No Auth" on an Insomnia request no longer inherits its folder's credentials. A request set to send no authentication, under a folder that requires it, was sending the folder's credentials anyway.
- An OpenAPI API key declared in a cookie is no longer silently sent as a header. The request now imports with no auth set, rather than a credential going somewhere the API never asked for it.
- A JMeter sampler's Follow Redirects / Redirect Automatically setting is now carried over on import.
- A JMeter response assertion checking the sampled URL now maps onto the request's URL rather than its body; one checking something else Vayu has no field for (request data, request headers, response message) is flagged instead of silently checked against the wrong text.
- A JMeter If/Switch/infinite-loop controller Vayu could not translate now shows up in the import summary instead of disappearing with its logic unexplained.
- An OpenAPI security scheme with no recognizable OAuth2 flow now imports with no auth set, instead of a plausible-looking but nonfunctional configuration.
- An OpenAPI OAuth2 flow's refresh-token URL is now imported.
- An OpenAPI 3.1 document whose operations are declared under webhooks no longer imports silently as zero requests.
- A Postman request body switched off in Postman is no longer sent anyway on import.
- A Postman request's client certificate or proxy override, and a JMeter file upload, are not yet imported but now show up in the import summary rather than vanishing without a trace.
- Smaller OpenAPI fixes: a parameter described only through its content type now keeps its example value, a 3.1 tuple-shaped array schema samples each position instead of coming back empty, and a deprecated operation is flagged in the import summary.
0.29.0 11 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.29.0 - 2026-09-11
Mock servers get a tab of their own, a per-request choice of which example they answer with, and a live log of everything they served. They also work from a browser now - a page calling a mock or a webhook inbox used to fail at the preflight while curl worked fine. The app gains a motion system across its menus, tabs and disclosures, and the History sidebar is a compact, day-grouped list.
Added
- A mock server tab, with the route table and a live activity feed side by side - the Services drawer's row expanded in place before, which a list that grows while you watch it does not fit. Each route shows its method, path, response mode and hit count, and the header carries the mock's added latency and failure rate. A running mock has an Open collection button and the collection's running-mock chip has an Open mock server button, so the two are one click apart in both directions.
- A request's Examples tab chooses how a mock answers it: the first example, a specific one, or a random pick per request. The choice is stored on the request, so it survives a restart and rides along through OpenAPI export and re-import.
- Every request a mock serves is recorded - path, status, which example answered (or that nothing matched, or that the failure rate injected the error), and when. The feed is bounded, so a mock left running does not grow without limit.
- MCP gains get_mock_activity for that log, and update_request now takes mockResponseMode and mockExampleId.
- New environment and Import environment are available from the title-bar environment switcher, which could previously only switch between environments that already existed.
- A run's entry in History shows the request's name when it had one, instead of only its URL.
- Requests, responses and collections remember which sub-tab you were last on, per item, instead of resetting to the default every time you switch workspace tabs.
Changed
- Motion is now a system rather than a per-component decision. Menus, tooltips, popovers, selects and toasts share the dialog's open/close curves; switching a tab fades its content in and slides the active indicator; every expand and collapse animates its height. A button whose label changes in place - Send, Save, Copy, Restart Engine - crossfades between the two words at a fixed width, so the row no longer reflows; the Send button's spinner is gone with it.
- History is a one-line row per run, grouped under Today / Yesterday / a date, so a relative time is said once per day instead of once per row. Up/Down/Home/End move between rows and Enter opens one; moving focus never opens a run on its own.
- Deleting a collection that has mock servers running under it names them in the confirmation dialog and stops them once you confirm.
- Electron 44.2.0.
- Internal: nested cards flattened into hairline lists, several hand-rolled controls replaced with the shared tab, toggle and list-row primitives they duplicated, app/src/utils folded into lib, and documentation kept in step with all of it.
Fixed
- Mock servers and webhook inboxes answer browser callers. Both run as their own listener and neither sent CORS headers, so a page calling one failed at the preflight; a preflight is now answered with 204 before any capture, latency or injected failure applies, and a sandboxed or file:// page's null origin is echoed without credentials.
- A mock replaying a captured example no longer forwards the Content-Encoding of the original transfer. The stored body is already decoded, so a browser failed the whole request with a decoding error before any of it was visible.
- A scenario run's report no longer stops at 100 steps. Past that, steps the run had actually executed and stored were silently missing from the view.
- A collection run's tab is named for the collection it ran, instead of "Design run".
- Reopening a finished run while its report loads says so, instead of saying it is waiting for the first step to execute.
- The Load Test dialog no longer fail
0.28.0 10 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.28.0 - 2026-09-10
Vayu can now import a JMeter .jmx test plan directly. The sidebar is reorganized into a left activity rail and a right context rail, replacing the single bottom dock. Pre- and post-request scripts get {{variable}} hover, click-to-edit and autocomplete back - on requests, and now on a collection's own script elements too. Controllers and timers that were sequential-only in 0.27.0 (control.switch, control.loop) now run under load, and a single-request load run gets the same setup/teardown scripts and per-request elements a full collection run has.
Added
- Import a JMeter test plan. A .jmx file maps onto Vayu's own elements: HTTP samplers, JSON/regex/boundary extractors, all five assertion kinds, all four timer kinds, and six logic controllers become folders. A component the importer does not map (a listener, CookieManager, CSVDataSet) is counted by name rather than silently dropped.
- Elements round-trip through OpenAPI export and import, in the spec's x-vayu-elements extension - previously dropped on export, so a request's extracts, assertions and scripts survived only inside Vayu.
- extract.boundary: reads the text between a left and a right marker out of the response body into a variable.
- timer.throughput: waits to hold a request, folder or collection to a rate ("N per minute") instead of a fixed gap - the rate-based sibling of timer.pacing.
- Custom metric budgets, from the run dialogs. Both the Run Collection and Load Test dialogs get a repeatable "Custom metric budgets" list beside the built-in pass/fail budgets - a metric name, a stat (p50/p95/p99/max/value/rate) and a ceiling. A run that recorded no custom metrics shows no chart for them; one that did gets a chart live during the run and in its history entry.
- Scripts show their variable references again, in place. pm.environment.get("token") and its pm.*.get siblings, and every {{name}} inside a pm.variables.replaceIn(...) template, are painted in the variable colour with a hover card (current value, source scope) and ⌘-click or ⇧⌘D to edit - the same affordance the request/response body editors already had. A bare {{name}} elsewhere in a script is muted, since the engine never interpolates one there, and its hover explains why and names pm.variables.replaceIn as the fix. This now also works on a collection's own script elements, which can write global, collection and (whenever one is selected) environment variables the same way a request's own script can.
- A settings entry can depend on another being on. correlationIdHeader is spliced right under correlationIdEnabled, indented and disabled with a "Turn on Correlation ID to use this" hint until the parent is switched on.
- Open logs folder, in Settings → General, opens the app's log directory in the OS file manager. Renderer errors (an uncaught render error, an unhandled rejection) now reach the same log file engine events do.
- maxElementBodyBytes is a real, adjustable engine setting bounding how much of a response body an element can read - previously fixed at 1 MiB regardless of what the docs claimed.
- A single-request load run can declare lifecycleElements (script.setup/script.teardown, run once at the run's start and end) and requestElements - the same extract/assert/timer/script elements a design-mode request has. GET /runs/:id reports that run's own element pass/fail/skip tally, shown in a new card on the Overview tab.
- The History sidebar shows a warning triangle beside a run's baseline chip when the run has warnings.
Changed
- The sidebar is a left activity rail plus a right context rail, replacing the single bottom dock's mix of view switchers and a context-bar toggle. The rail's six buttons switch views; the context rail holds one icon per applicable section - click to open, expand or scroll to it, click again to collapse.
- control.switch and control.loop now run under a load test, capped by the existing per-iteration step limit - both were refused there in 0.27.0. control.throughpu
0.27.0 8 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.27.0 - 2026-09-08
Two things to read before updating: this release fixes a macOS bug that stopped 0.26.0 from starting at all on most Macs, and it converts your saved scripts to the new element model in a one-way database migration, so a workspace opened by 0.27.0 cannot be opened by 0.26.0 again. Beyond that, the collection run gains most of what a JMeter test plan does: extracts, assertions, timers, controllers and transactions you attach to a request or a folder, plus custom metrics, pass/fail thresholds on every run mode, and setup/teardown scripts that run once per run.
Added
- Elements: typed behaviours you attach to a request or a folder. Extract a value into a variable, assert a status or a JSONPath, wait between steps, loop or branch, record a metric - each added, reordered and switched off on its own, inherited by everything under the folder it sits on, and disabled on a single request without deleting it from the parent. Requests and collections each get an element list with a form per kind. Scripts are elements too, which is what the migration under Changed is about.
- Controllers. control.if runs a step only while a condition on a variable holds, control.once runs it on that user's first iteration only, and control.throughput runs a share of the occurrences by percentage or every Nth pass. On a folder, control.loop repeats its requests a set number of times, control.switch jumps to the member a variable names, and control.transaction sums its requests into one named transaction that the report carries with its own count, errors and latency percentiles. control.switch and control.loop are sequential-only: a load run declaring either is refused with a message naming it, since a virtual user has no way to jump backwards.
- Timers. timer.think waits a fixed time, a uniform random range, or a normal distribution around a mean, between steps - so the wait never counts against either step's latency. timer.pacing holds a request, a folder or a whole collection to a steady start-to-start cadence whatever the step's own duration was, per virtual user or shared across all of them. Both are reproducible from a run's elements.seed, and a Stop lands during a wait instead of after it.
- script.setup and script.teardown, which run once at the start and end of a run rather than per step - the place for a login that should happen once, or a cleanup that should happen even after a failure.
- Custom metrics. pm.metrics.trend, .counter and .rate in a script, or the metric.record element without one, record your own numbers alongside the built-in ones. The run report shows them as a card with the distribution for a trend, the total for a counter and the percentage for a rate.
- Pass/fail thresholds on collection runs, not just load runs. A run declaring thresholds is judged against its budgets and the report carries a verdict per budget. New in this release: maxAssertionFailureRatePct, a ceiling on the share of assertions and pm.test calls that failed however they ran, and thresholds.failRun, which makes a missed budget mark the run failed rather than merely reporting it. A budget whose metric got no samples is reported as unevaluated instead of silently passing.
- MCP agents can read and write elements. The request and collection tools carry them, run_request takes ad-hoc elements for one call without saving them, and an elements/kinds resource lists every kind with its schema so an agent can build a valid one without guessing.
- pm.cookies is readable from inline load-run scripts.
- The Run Collection dialog can override timers and scripts for one run, and the same override is available on the MCP run tools.
- Engine logs are structured. Every line in the log file is one JSON object with a timestamp, level, category and message, and values that used to be baked into the sentence are fields. Values are redacted by key, so a token in a logged object does not reach the file. The console rendering is unchanged in spirit and still gover
0.26.0 5 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.26.0 - 2026-09-05
This release moves to Electron 44, which drops macOS 12, and changes the application identifier. Read the first two entries under Changed before updating. Beyond that it is mostly desktop integration: system notifications, taskbar and Dock progress, a keep-awake option for long runs, right-click menus outside the editors, and Back/Forward across tabs. The engine now owns the default headers it adds, the Windows uninstaller actually deletes your data when you ask it to, and a failed run is finally reported as failed.
Added
- System notifications. A finished load or collection run, the engine going down, an update becoming ready, and a browser sign-in completing can now post an OS notification. Off by default (Settings > Notifications), and nothing is posted while Vayu is the front window. The run notification carries the numbers ("12,400 requests, p95 210 ms, 0.3% errors") and clicking it brings Vayu forward on that run. A Preview button next to the toggle posts a real one so you can see what your system does with it.
- Inbox capture notifications. Off by default even when system notifications are on, and toggled in the inbox header rather than in Settings. Captures are batched into one trailing notification with a count, since a webhook source can deliver hundreds a minute. An interrupted capture stream now resumes.
- Taskbar and Dock progress. A running load or collection run shows its progress on the Windows taskbar button and the macOS Dock icon. Captures that arrive while the window is unfocused show as a badge count, and a failed run marks the icon. A run that ends in a state you did not ask for flashes the taskbar or bounces the Dock once, but only when system notifications are off. If two runs are live, the most recently started one owns the indicator. No progress bar on Linux: Electron 44 removed Unity launcher support.
- Dock and taskbar menu, and file handover. Right-click the icon for New Request and your recent collections. Dropping a Vayu-openable file on the icon, or opening it with Vayu from the file manager, opens the Import dialog on it. This works from a cold launch too.
- Runs started through the MCP surface get the same progress indicator, keep-awake hold and notifications as runs started from the UI. Previously none of that kicked in until you opened the run's dashboard tab.
- Keep awake during runs. Vayu can hold the machine out of sleep while a run streams (app suspension only; the screen may still dim). Off by default. Keep awake during runs in Settings > Load testing turns it on for every run; with it off, a load run declaring ten minutes or more asks once as it starts. A run with no declared length is never asked. If the host sleeps anyway, the run reports how long it slept instead of leaving a gap in the series.
- Right-click menus everywhere, not only in the Monaco editors. The URL bar, a {{token}}, an editor, tree rows and tabs each get their own menu, with cut/copy/paste, selection and link entries where they apply.
- Back and Forward across tabs. Title-bar buttons, Cmd+[ / Cmd+] on macOS and Alt+Left / Alt+Right elsewhere, the mouse back/forward buttons, the macOS two-finger swipe, the View menu and two palette commands. History is by location, not tab instance, so Back can reopen a tab you closed; closing the active tab returns to where you came from. Deleted requests and collections are dropped from history.
- GraphQL schema explorer: arguments as rows. A field's row shows its result type and an argument count; the arguments expand as rows underneath. Activating one writes first: $first onto the field and declares $first on the operation. Previously the inline argument list ate the width and users (first: Int, userId: In… never showed what it returned.
- resolve_variables MCP tool. Ask it about a variable name and it lists every definition in precedence order (globals, then the collection chain root to leaf, then the active environment), marks the one that wins, and says for
0.25.0 3 de setembre del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.25.0 - 2026-09-03
The performance and accessibility release. Vayu used to spend its first second parsing code nobody had asked for and then waiting on the engine before drawing anything; the renderer's module graph is now a fraction of what it was, the window opens alongside the engine rather than behind it, and the memory a long session accumulated is bounded on every axis it grew on. Alongside that, the app became operable from the keyboard end to end - the trees, the tabs, the editors and the regions between them all have keys now, and focus stops falling off the page. The rest is precision work in the editors and the GraphQL pane, one inbox route that had been answering 404 to requests it should have recorded, and a batch of engine hygiene.
Added
- The tree row menus, the variables sidebar and the regions between them are keyboard-operable. A collection or request row opens its actions with Shift+F10, the Menu key or Shift+Enter, and the tree is one tab stop with roving focus rather than a tab stop per row; the variables sidebar became the same kind of tree, so rename and duplicate finally have a key. F6 and Shift+F6 cycle the app's regions in both directions, which is the desktop convention Explorer and Firefox already use and the one move that makes every other surface reachable without a pointer. A tree row's parent is now read off aria-level rather than off the DOM shape, so the structure a screen reader is told about and the structure the keys walk are the same one.
- Six chords for the moves that had none, and a palette that lists them. New request, focus the URL, next and previous tab, leave the editor, and edit the variable under the cursor. Each appears in the command palette with its chord printed beside it, and a parity guard holds the two in step, so a chord that exists and a palette row that runs it cannot drift apart.
- Send from the command palette. It runs against the request builder's live draft rather than the last saved copy, which is the only reading that matches what the Send button does.
- A palette that leads with Recents and the verbs. Quick actions, recent requests, chord chips on the rows that have one and a hints footer, with the two lead sections kept disjoint so nothing is offered twice, and one ranking authority behind the whole list rather than a per-section order.
- {{variable}} tokens are coloured, explained and editable inside the editors. In the body and GraphQL editors a token is now painted by what it resolves to - defined, undefined, or a run-time name - with a hover that gives the value, the scope that answered and any scopes it shadows, secrets masked. Cmd/Ctrl+click or Shift+Cmd/Ctrl+D opens the same variable popover the rest of the app uses, so editing a value no longer means leaving the editor to find where it was defined.
- Variable completion in an XML body. The offer is derived from the body-mode table rather than from a second list that had to be remembered, so a mode that gains completion gains it once.
- The Windows installer publishes its .exe.blockmap. This is what lets electron-updater compare the release being installed against the one being upgraded from and range-request only the blocks that differ. This release is the first to carry one, so the release it upgrades from has none, that fetch 404s and the fallback runs: Windows users download the full installer one more time, and the saving starts with the next release.
Changed
- Startup no longer pays for code the first screen does not use. The renderer was a single eager entry chunk that parsed Monaco, the GraphQL packages, the markdown pipeline and all eight feature surfaces before a window could be shown. The tab surfaces and settings panels are behind React.lazy, Monaco loads on the first editor mount through one loader that owns the ordering (a naive defer would have made @monaco-editor/react fetch the editor from a CDN and fail offline), the six typefaces are bundled and subset instead of fetched from Google Fon
0.24.0 29 d’agost del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.24.0 - 2026-08-29
The compatibility and durability release. Three threads run through it. The pm.* scripting surface stopped being a subset and became the API imported collections actually reach for: pm.request.url and pm.request.body are Postman's own Url and RequestBody objects, pm.sendRequest composes auth and resolves {{variables}}, chai's language chains read as English, and the dynamic-variable table went from 15 names to 39. A load run now has an identity - {{$vu}}, {{$iteration}} and a {{$guid}} family that regenerates per iteration rather than being frozen at composition - so a data-driven run varies on three axes instead of one. And the workspace stopped being a single file with nothing standing behind it: deletes are soft and restorable, POST /workspace/backup writes a snapshot you control, a corrupt database is quarantined rather than destroyed, and the log directory is bounded on all three of the axes it used to grow on. The bulk of the change is engine C++; the app carries the Trash drawer, the undo, and every surface that had to learn the two new reserved namespaces.
Added
- A Trash, with restore, undo and a retention window. Deleting a collection was irreversible with a confirm dialog as the whole safety net. DELETE /collections/:id and DELETE /requests/:id now stamp a nullable deleted_at instead of removing rows - a collection's cascade stamps its subtree in one transaction - and every read surface filters stamped rows out, so the tree each client sees is the one a hard cascade would have left. GET /trash lists the deleted roots with what their cascade took along, POST /trash/:id/restore clears the stamp, DELETE /trash/:id is the old hard cascade asked for deliberately, and a startup sweep purges anything older than trashRetentionDays (default 30; 0 keeps the trash forever). Two rules make a restore precise: one delete stamps its subtree with one timestamp and a restore clears exactly that timestamp, so restoring a collection cannot resurrect a request deleted separately beforehand; and a restored collection whose parent is gone comes back at the tree root, while a request whose collection is still in the trash is a 409 naming the collection to restore first. The app gets a sixth drawer view over it - cascade counts, because a folder in the trash is otherwise indistinguishable from an empty one, and a retention sentence read from the setting rather than written into the copy. The delete toast now offers the undo the dialog always implied, and the undo gives back what a restore alone cannot: the focused tab that was closed and the collection's remembered data-file path, both captured in the closure before the mutation runs. MCP closes the same loop with list_trash, restore_trash_entry and purge_trash_entry, the purge double-gated exactly like delete_collection.
- On-demand workspace backups. Everything a Vayu user builds lives in one SQLite file and there was no copy of it they controlled - the .bak the constructor writes is rewritten on every clean start, and copying the file by hand while the engine runs is unsafe under WAL. POST /workspace/backup (with a CLI verb beside it) writes one snapshot into backups/ with SQLite's VACUUM INTO: consistent under WAL, compacted, and on a connection of its own so a large copy does not park every other endpoint behind it. Names are UTC and fixed-width, so retention sorts them as text rather than trusting an mtime; the newest maxBackupsRetained (default 5) are kept and only files matching that name are ever removed, so a copy you put in the directory survives. A second concurrent backup is refused with 409 through a single RAII-held slot. Restoring is a file copy you perform yourself, which is why the response's whole point is the path.
- A load run carries an identity: {{$vu}} and {{$iteration}}. Which virtual user this request belongs to (1-based) and which of that user's iterations it is (0-based). They are reserved names rather than variables - a variable of either na
0.23.0 23 d’agost del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.23.0 - 2026-08-23
The keyboard release. A review of every key the renderer listens for found that the chords were not really a system: fourteen bindings were hand-rolled in the Shell against e.key behind a raw e.metaKey || e.ctrlKey, six of them re-derived as independent label literals in the Dock, and the registry that constants/shortcuts.ts promises in its own header was true of neither. Two of the gaps were live misfires on layouts nobody here types on - AltGr is Ctrl+Alt on many European Windows layouts, so typing @ closed the tab, and the digit chords compared against characters AZERTY's digit row does not produce. Consolidating them onto one registry is what made the rest possible: chords are now inert behind a modal, they survive an IME's Enter, they work on a Mac keyboard's delete key, and for the first time they are listed on a screen. The engine side of the release is not a feature but a floor: C++23 is on, -Werror is a gate, and clang-format and clang-tidy went from three layers of advisory nothing to checks that fail a build.
Added
- Settings > Keyboard shortcuts. Cmd/Ctrl+W, +B, +I and +1-9 appeared nowhere in the app: the Dock advertised the drawer switchers, the URL bar advertised Send and Load Test, and everything else lived in a handler and a doc. The panel holds no list of its own - each chord definition carries its label, SHORTCUT_GROUPS groups the same objects, and the key-caps render through chordKeys, the function the Dock's tooltips already use. A table of names and keys sitting beside the registry is exactly the defect the consolidation removed, so the surface is derived or it is nothing. The command palette gains the row for free, since it already generates one command per settings panel. Read-only for now: rebinding is a store, a persistence format, a conflict check against the native menu and a matcher that reads user data, and it is tracked separately.
- The app tells you when a corrupted database was deleted. The engine already deleted a database it could neither open nor restore from its .bak, so the daemon starts instead of crash-looping forever; the entire record of it was two lines in the engine log, while every collection, request, environment, saved example, spec document and run was gone and the app came up looking like a fresh install. The fact cannot live in the database, because the database is the thing that just went away, so the recovery branch writes a JSON marker beside it, GET /health reports it as a recovery node that is absent on a clean start, and the app renders a dismissible banner naming the path. Presence alone distinguishes a wipe from a genuine first run, because a clean start writes no marker; the engine never clears one, since it can be restarted before any client polls, so showing the notice once is the reader's job and the app does it by persisting the timestamp it acknowledged rather than by holding component state - a second window against an already-running engine would otherwise re-announce a wipe that had been dismissed.
- The engine is C++23. The standard flip is the smaller half. The routes' "error or nothing" type was std::optional<std::pair<int, nlohmann::json>>, where an empty optional meant success: if (err) was the failure path, return std::nullopt meant "fine", and a dropped return value silently meant "no error", which is why the two most dangerous appliers carried [[nodiscard]] by hand. It is now std::expected<void, RouteError> with named status and body, so propagation reads forwards and the response is reachable only through .error(). The whole family moved together - appliers, guards, per-file builders - because converting half of one idiom would have left an adapter at every boundary between the halves. Inbox parsers followed the same way, returning std::expected rather than an optional standing in for an error. std::move_only_function is deliberately still out: AppleClang's libc++ has not shipped it, and no runner pin fixes a library gap.
- The pre
0.22.1 21 d’agost del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.22.1 - 2026-08-21
A follow-up to the import progress release, and both entries are the same shape of defect: work that outlived the state it was started for. Switching tab in the import dialog did not stop a URL fetch and could not, because all three tabs shared one set of state - so the download landed under whichever tab you had moved to. And closing the dialog did not stop the download either, which 0.22.0 said it did. Renderer only; the engine is untouched.
Fixed
- A URL fetch landed on whichever import tab you were looking at. The dialog kept one phase, one entries, one error and one progress for all three tabs, and switching tab called a reset over them - which cleared the display of work that went right on running. So a document fetched on the URL tab appeared under the File tab's dropzone when it arrived, and the URL you had typed was already gone. Each tab holds its own state now: a switch only switches, an in-progress download stays where you started it and is still there when you come back, and two tabs can hold two results at once. Every async writer patches the tab it started on rather than the one showing when it finishes, which is the part a test can actually hold down. The two option checkboxes stay dialog-wide, so toggling one re-parses every tab holding a parse rather than only the visible one - re-parsing just the one on screen would leave the other holding a parse made under the old options, and importing it later would apply a setting the checkbox says is off.
- Closing the dialog now stops the download - which 0.22.0 claimed and only half did. The transport was right: httpClient.stream released its reader as soon as its consumer stopped iterating, and the engine abandons a transfer the moment a write to its SSE sink fails. Nothing ever made the consumer stop. importFetch sat in the loop on the dialog's behalf and ran to completion, so closing the dialog left the engine reading the rest of a 10 MB document for nobody. An AbortSignal threads through both and the close fires it: measured against a local server, 3216 KB served at the click and not one byte more over the next six seconds, with about 2 MB still to go. An abort raises an AbortError, deliberately distinct from the idle stall's Request timeout - both end in an AbortController, and a deliberate cancel reported as a timeout is a banner about a failure nobody had, waiting for the next time the dialog opens. The v0.22.0 note has been corrected in place rather than left standing.
- Closing the dialog mid-detect left a ghost preview behind it. The close never blocked on the detecting phase, so a $ref walk or an engine parse already in flight finished afterwards and wrote its preview into the state the dialog next opened with. A per-tab generation counter, bumped by a close or a reset and checked before every write, covers that along with the fetch, an option re-parse and the apply's outcomes - four kinds of write that an abort path per stage would not have reached.
0.22.0 21 d’agost del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.22.0 - 2026-08-21
The import progress release. Pointing the import dialog at an 8 MB OpenAPI document froze it: POST /import/fetch could not say a word until libcurl held the entire body, so the File tab showed its untouched dropzone for the whole of a 13-file folder pick and the URL tab changed one word on a button for the whole of a download. The phase that meant "working" was set in three places and read by nothing that renders - "written but never read" again, which is this codebase's most repeated defect. The engine now reports a download as it arrives, over the same SSE framing the run topics use, and the dialog draws it. Building that turned up the reason a large URL import failed even when you could see it working: the route inherited a 30-second bound on the whole transfer, which is a bound on a document's size rather than on its health. Roughly even split between new C++ in the engine and new React in the app.
Added
- The import dialog says what it is doing, and how far through it is. Four stages, because they are four genuinely different waits: the download from a URL, the $ref walk across disk or the network, one engine round trip per document to read it, and one atomic write per document to store it. Naming which one is running is half the report - "Importing" during a two-minute download would be a lie about what is taking the time. Every total is a real count of real work, and the one that is easiest to get wrong is the parse: its total is the documents that will actually be parsed, which is fewer than the documents picked whenever one could not be read or was inlined into another, and a total that counted those would leave the bar permanently short of itself. A download whose upstream declared no Content-Length has no denominator, so it reports bytes received against an indeterminate bar rather than a percentage of a number nobody stated - and reports itself to assistive tech as busy rather than as "0 percent", which for a half-finished download would be a fraction no one measured. Reading the picked files off disk gets a name but no counter: FileReader is local and effectively instant, and a number there would be motion without information. The counters do not change what the work does - detectBatch still bundles and parses the whole batch in one wave each, ticking as promises land, because serializing them for a tidier-looking number would trade a 13-file folder's wall time for cosmetics.
- POST /import/fetch can answer as a stream. With Accept: text/event-stream the route emits progress ({received, total}, total null when the upstream declared no length) and then one terminal result or error carrying exactly what the buffered form would have returned. The report comes off libcurl's write callback, which is the only place that knows a byte has arrived; streaming the engine-to-renderer hop would have changed nothing, because the wait is on the upstream download. Frames are throttled to 256 KiB or 100 ms, since libcurl reports every ~16 KiB and a 10 MB document would otherwise be ~640 frames for a bar with a few hundred pixels to cross. Two consequences of the response headers having already left: a malformed request is still a 400, decided before anything is written, and a failed fetch is an error event carrying the numeric status itself - the standard error body's code is a slug, and 413 and 404 both slug to plain error, so a client could not otherwise tell a refused-for-size document from any other failure. Every caller that sends no Accept - $ref bundling, spec re-fetch, the MCP tools - gets the byte-identical JSON it always did.
- Closing the dialog stops the download. The engine abandons its transfer the moment a write to the SSE sink fails, rather than reading the remaining megabytes for a listener that has gone, and the renderer's side of that is cancelling the body stream when it stops iterating. Measured against a local server: 1.31 MB served when the client hung up, and 0.25 MB more over the next t
0.21.0 20 d’agost del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.21.0 - 2026-08-21
The data-row release. Everything here was found by writing one collection that tries to exercise a data-driven run end to end, which is the cheapest way to discover that three separate layers disagreed about what a {{data.column}} token means, what a JSON body is, and whether .not negates. The script sandbox stops being the odd one out - pm.variables.replaceIn resolves the data namespace the way a URL, a header and a body already did - a JSON body finally declares itself as JSON on the wire instead of inheriting libcurl's form default, and an assertion chain with two negations in it means what it says. On the app side the data-row picker stops being a popover it could not fit in and becomes a grid you can actually read a row out of, and dragging a request past a collapsed folder no longer springs it open under the pointer. Small release, and the shape of it is corrections: three engine defects that were each invisible from inside the layer that had them.
Added
- {{data.column}} resolves inside a script. pm.variables.replaceIn was the one template resolver in the product that disagreed with the others about the data namespace: a URL, a header, a body and an auth credential all bind {{data.userId}} per iteration, and handing the same string to replaceIn returned it with its braces still on - which reads as "unresolved variable", the same output an unknown {{$typo}} gives, so nothing said the row was available and simply not consulted. It resolves now, against the row bound to the iteration, and brings the binding's own three rules with it rather than inventing softer ones. A column the row does not carry is a TypeError naming the token and the columns the row does have, not "" and not the token verbatim: the token says the value came from the file, so a name no column answers is a mistake about the column and both quiet answers hide it. With no row bound at all the token keeps its braces, unchanged, because a plain design send has no row by design and a shared script that guards with pm.iterationData has to run in both modes. And the namespace stays reserved rather than becoming another precedence tier - {{userId}} and {{data.userId}} are still different names, so a data set cannot shadow a variable or be shadowed by one. Deliberately stopping at replaceIn: pm.variables.get and .has read the variable scopes, and the row is not one of them, with pm.iterationData as its accessor. The distinction is that replaceIn resolves a template, and this is a token template syntax has.
Changed
- The data-row picker is a grid you can read a row out of. Send's caret opened a 384px popover anchored over the response pane, and every compromise in it came from that box rather than from the feature: a row was one truncated line with its column name printed in front of every value (userId=1001 email=ada@example.com plan=pro q…), the list stopped at twenty rows, and a row-number field stood in for the rows there was no room to show. Picking a row meant reading a sentence instead of scanning a column, and row 21 was reachable only by already knowing its index - which is the row a long run's failure names. Choosing a row out of tabular data is a browse, so it is a dialog now: the columns are named once in a sticky header, every row in the file is in the grid, and a filter narrows them by any value in any column. The number field survives, demoted from the mechanism to a shortcut for jumping to row 480 of 500. Clicking a row still sends outright, because the one-click loop is the whole reason the feature exists; the footer's Send row N is for a row reached by typing or by arrow keys, and it names the row so a jump is confirmable without hunting for it. Rows arrive as they are scrolled to, so a thousand-row set costs a screenful of DOM rather than a thousand rows of it - the one thing the popover was right about, kept. The grid is a real ARIA grid with a roving tabindex, so a large file is one tab stop instead of one per row. This ope
0.20.0 20 d’agost del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.20.0 - 2026-08-20
The contracts and certificates release. Two long-running moves finish. Everything that reads a document - an OpenAPI spec, a Postman collection, an Insomnia export - now reads it in the engine, so there is exactly one opinion about what a document says: the reader, both indexes, operation matching, request drafts, the sync diff, spec export and every import parser move out of the renderer, and an MCP agent can bind a collection to a spec, ask whether the contract has drifted, apply that drift under a policy that will not overwrite a person's edits, export a spec and import a document. Alongside it, client-certificate (mTLS) support grows a per-host registry that answers for every subdomain, ships PKCS#12 as well as PEM, and runs on one OpenSSL backend the engine names for itself on all three platforms, so Windows gets a working mutual-TLS handshake for the first time. The app adds a system proxy mode with a connection test, and a collection run's step list gains search, a way back from a step to the request that produced it, and the ability to scale to thousands of steps. The shape of the release is that move: the engine grows about 10,000 lines of new C++ while the renderer sheds roughly 7,700 net, most of it parsers and comparators that now have a single home.
Added
- The OpenAPI stack runs engine-side, end to end. The engine could not read a stored document at all, so every question about one was answered twice - once by the renderer's parsers and once by whatever the engine derived - and two readers disagree exactly where it matters. core/openapi_document is now the one translation unit that includes a YAML library, and rapidyaml (ryml) was picked by measurement against js-yaml, the reader the importer already used: it matches on every corpus file, keeps document order, and parses a 2.9 MB / 4,000-operation spec in 33 ms, where yaml-cpp turns the string "2.0" into the number 2.0 (which is what Swagger detection reads) and fkYAML sorts mapping keys. Scalars are typed by js-yaml's core schema, anchors, aliases and merge keys expand the way js-yaml expands them, a duplicate mapping key is refused, and expansion is bounded at one node per input byte - without which a 300-byte alias bomb reads for 7.9 seconds and gigabytes. On that reader: spec_documents.operations is derived on every write and refused in the body, so the index is a fact about the stored bytes the way hash is; the response schema index is derived off the same single walk, including OpenAPI 3.0's schema dialect translated to JSON Schema and a response object that is itself a $ref; POST /specs/match owns operation matching, ambiguity refused in both directions rather than guessed at; the engine can answer, for a stored document, the requests an import of it would build - method, URL, params, headers, sampled body and the folder each is filed under - off the same walk the indexes come from, which is what the sync diff compares a stored request against field by field; POST /specs/describe answers a picked document's format, title and operations so the bind preview and the bind commit read the same bytes through the same reader; POST /specs/bind does the whole bind in one transaction, matching the subtree itself and clearing the stamps a re-bind orphans; POST /specs/diff is the sync comparison, reading the bound document from the binding and walking the collection's subtree itself, because the three-way user-touched rule is worth nothing if the caller can supply the previous side; and POST /specs/export assembles the document, patching a bound collection's own stored bytes rather than regenerating (a regenerated document silently drops every security scheme, vendor extension and description Vayu has no model for) and inventing nothing for an unbound one. Each move is pinned to the renderer's own answers by a cross-language conformance fixture rather than to its code, because a draft the two sides build differently reads as "the document changed t
0.19.0 19 d’agost del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.19.0 - 2026-08-19
The agents and transport release. Two epics land side by side. MCP stops being the read-mostly half of Vayu: an agent can now run a whole collection in design mode or under load, start and drive mock servers and webhook inboxes, create and switch environments, read and clear the cookie jar, write a saved request's auth and every Settings field, curate its examples, and keep run history - roughly thirty new tools over routes the engine already had. Underneath, the engine gains one transport policy that every outbound path inherits, carrying manual proxies, pasted CA anchors, per-request verifySSL and a per-host client-certificate registry, so an internal or mTLS-protected API is callable at all. The OpenAPI work 0.18.0 started gets its follow-through - a bound spec is described rather than transferred, a document-level change is applyable, and orphaned documents are reclaimed - and the dialog primitive learns to fit on a screen. The bulk of the change is new TypeScript in the app's MCP server and new C++ in the engine's transport layer.
Added
- One transport policy, and a manual proxy on every outbound path. The engine had proxy readers and no writer: proxy_url sat in two config structs that nothing ever assigned, SSE had no proxy option at all, and the only proxying Vayu did was libcurl's implicit environment pickup, which a desktop launch never sees. TransportPolicy is resolved from settings at the point of use and applied by one function for all three drivers, so a transport option cannot land on two paths and miss the third - which is exactly how SSE never got a proxy. Design sends, pm.sendRequest, load runs, collection runs, SSE streams, the OAuth token fetch, /import/fetch and the monitor scrape all inherit it, and the load and collection paths read it once per run because libcurl only reuses a pooled connection when its proxy config matches. Modes are environment (today's behaviour, named), manual and off, where off genuinely disables the env pickup; manual always writes the bypass list, empty or not, since libcurl consults the ambient no_proxy whenever CURLOPT_NOPROXY is unset. A refused CONNECT becomes ErrorCode::ProxyError rather than a plain receive error, read off CURLINFO_HTTP_CONNECTCODE - the only place a 407 survives.
- Custom CA certificates, and verifySSL end to end. A new customCaCertificates setting takes pasted PEM anchors, validates them, materializes a bundle beside the database and hands its path to the one applier, so the anchors reach every path the policy does. They extend the platform's rather than replacing them: on an OpenSSL build CURLOPT_CAINFO is the whole trust store, so the file is the system anchors plus the pasted ones, while Schannel and Apple SecTrust keep their OS store and the engine sets NATIVE_CA beside the bundle. A backend that refuses the option is named in the log rather than failing every later request with nothing saying why. verifySSL becomes a real column on requests carried through both serializers, POST /compose, the replay path and a Settings toggle that paints a warning while verification is off - never elided at its default, because a dropped false verifies the certificate the user opted out for. curl -k and wget's --no-check-certificate now import as that setting instead of being skipped, and the curl generator emits -k back.
- Client certificates (mTLS) as a per-host registry. Nothing in the engine ever set CURLOPT_SSLCERT, so an mTLS endpoint was uncallable. A certificate is a property of where you are calling rather than of one request - the transfer that needs it is as often a token fetch, a redirect or a script's pm.sendRequest - so this is a registry keyed by host and port, applied by the engine, and no request names a certificate. The private key never enters the database (paths are stored, and both are checked at write time, since an unreadable one otherwise surfaces at handshake as an SSL error that reads like "the API is broken"), one entry p
0.18.1 17 d’agost del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.18.1 - 2026-08-17
A follow-up on the contract stack v0.18.0 shipped. That release bound a collection to the spec it came from and built coverage, schema validation and sync on that identity; this one makes those engage on the paths people actually take. A binding written at import carried no version, so both features were inert on nearly every binding that exists. Running a tag sub-collection - what an OpenAPI import files every request under - resolved no binding at all. A response declared as a $ref, the shape GitHub's public spec uses almost everywhere, yielded no schema while coverage counted the same status as declared. And a duplicated operationId let a sync rewrite a request into an operation it never was. Beside those: two engine execution fixes, a refusal of bound data that would forge a header line, and a full per-entry audit of the engine settings tree. No new surface.
Changed
- The engine settings tree got a per-entry audit. The previous pass fixed the shelves; this one audits every entry against the words a user arrives with. Sixteen rows move and a new Limits category holds the six ceilings a rejection message names - the scenario and spec caps, maxStepsPerIteration, and maxResponseBodyBytes, which fails an oversized load-run read in flight and so is not retention. Core was a dumping ground of twelve entries under a description covering four of them, and keeps those four. The oauth2Refresh* family joins Services, beside the issuers the category description already named; the per-run storage budgets join Data & retention; phaseHistograms moves to Observability, being a measurement toggle rather than a retention budget. Five entries gain the advanced flag by a rule citable in review: if a description has to say "only if" or "only for", the entry has declared itself advanced. The moves are seed metadata only - your values are kept and an existing install migrates on next start - and a new guard asserts every moved entry is still findable under the words it is searched with, since the category label is the one search field that does not travel with an entry.
Fixed
- An imported spec's binding carries a version, and bindings written without one are repaired. Import stored {"specId": "..."} and nothing else, while contract coverage and response-schema validation each require the binding's specHash to match the stored document's before they engage. An empty hash never matches, so every run of an imported collection took the mismatch branch and reported no contract at all - while telling the user their document had moved under the binding, which it had not. The hash is now the engine's half on every write path: a client sends the specId, the only half it can know without a round trip whose answer is stale by the time it writes it, and one rule fills in the rest for both collection write verbs, for /import/apply, and for a startup pass that repairs the rows written before the rule existed. That pass stamps the document's fetched_at rather than now, because stamping months-old rows with the current time would say you synced today. A hashless binding also stops masquerading as a document that moved: it gets its own reason, never_stamped, whose remedy is re-binding - a sync of an unchanged document short-circuits on byte equality without touching the binding, so "sync the collection" was advice that could not have worked.
- Running a tag sub-collection of a spec-bound tree measures coverage and validates again. An OpenAPI import binds the root collection and files every request under tag sub-collections, so the most natural workflow - right-click the pets folder, Run collection - resolved no binding, measured no coverage and validated nothing, silently. The run path read the openapi column of only the collection the run named, while design-mode validation of the same request walked the ancestry to the nearest bound collection; both now resolve through one function over the chain request composition already walks for inheri
0.18.0 16 d’agost del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.18.0 - 2026-08-16
The OpenAPI release. v0.17.0 could read a spec and make requests out of it; the document was then thrown away, so nothing downstream knew a contract existed. A collection now binds the document it answers to, every request remembers which operation it is, and that identity is what the rest of the release is built on: re-fetch and diff the spec, apply the diff selectively in one transaction, export the collection back out as a document, and judge what came back against the schemas the spec declares - in design mode, in a collection run and over a load run's samples - beside a coverage block saying which of the contract a run actually exercised. Streams grow the other half they were missing (a load run may now consume text/event-stream, with events on its sampled captures), a single Send can carry one data row, and a live response can be saved as an example. The bulk of the change is new TypeScript in the app, with the validator, the coverage tally and the streaming load path landing engine-side.
Added
- A collection binds the spec it came from, and every request knows its operation. An OpenAPI import now stores the document verbatim in a new spec_documents table with an engine-computed hash, binds it to the root collection, and stamps each request with the operation it is (operationId when declared, plus the method and the templated path). A document is bound rather than owned - several collections may bind one, so nothing cascades to it and deleting a spec that a collection still holds is a 409 naming the binder. There is no PUT /specs/:id on purpose: a changed document is a new one, because rewriting in place would invalidate the hash every run of every bound collection was stamped with. A Spec tab shows the binding, unbinds it, and binds a collection that was never imported from a spec by matching operations to existing requests on method and path shape, disclosing the counts on both sides before anything is written.
- Sync: re-fetch a bound spec, see exactly what moved, apply only what you tick. The Spec tab re-reads the document from the origin the binding stored and reports the three buckets - added, changed, removed - as a checklist, with "up to date" meaning byte equality against the stored document rather than a second opinion computed in the renderer. An operation is followed by its operationId first and its path shape second, so a path moved under a stable id and an id moved under a stable path each stay one operation, while both-moved is disclosed as a removal plus an addition rather than guessed at. A field you edited yourself is flagged three-way and is never overwritten unless you tick it, and a deletion is never a default. Applying sends one POST /specs/sync that the engine performs as a single transaction over the document, the binding and the created, updated and deleted requests; the bound subtree is the boundary, so the route cannot become a way to delete an arbitrary row by id. On an update, only origin="import" examples are replaced - examples you saved survive untouched and keep their position, which is what a mock server answers with.
- Importing a document a collection is already bound to offers Sync. It used to make a second collection from scratch, without the bound one's operation identities, saved examples or coverage history, and with nothing anywhere saying the first existed. Import now looks the document up before it writes anything, by stored source_url or by the bytes, and names the collection it found. Import anyway is still there beside it: a second copy of a spec is a real thing to want, so this is a fork and never a block.
- Response schema validation, on all three execution paths. The app extracts what a document declares each response looks like and translates it out of OpenAPI's dialect rather than forwarding it - nullable: true and draft-04's boolean exclusiveMinimum mean something else under draft-07, and a wrong verdict is worse than none. The engine matches a resp
0.17.1 15 d’agost del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.17.1 - 2026-08-15
A follow-up release, on the wire behaviour v0.17.0 changed and on the release machinery that shipped it. That release made an imported request's query string actually reach the target - url is the wire truth, so every parser's params[] is now joined onto it at parse time. That fix was right, and it exposed a decision the OpenAPI importers had never had to make: a spec lists every query parameter an operation accepts, and they all imported enabled, so a declared-but-optional parameter started riding along on every send as a bare key. The only user-facing change is in the two OpenAPI parsers; the rest is release CI, where v0.17.0's own build had rebuilt every C++ dependency from source and its winget submission had pruned the wrong versions.
Fixed
- An imported OpenAPI operation no longer sends parameters the spec only documented. A spec declaring an optional verbose with no default imported it enabled and empty, so the stored URL became {{baseUrl}}/pets/{{petId}}?verbose and every request carried a bare key - which some APIs read as verbose=true. Before v0.17.0 the stub never reached the wire at all, so this was a behaviour change nobody chose. An optional parameter with no declared value now imports disabled: the row is still in the Params table, one click from use, and out of the URL. Two things override that and only two - required: true, because a spec saying a parameter must be sent is an instruction rather than documentation, and a declared value, which is now carried into the row instead of being dropped, so a default: 25 sends ?limit=25 rather than a valueless ?limit. Value precedence is the parameter's example, then its examples map, then the schema's example, then its default, following one $ref hop; Swagger 2.0 reads default, having no example keyword for a non-body parameter. An array or object value is left uncarried on purpose, since style/explode and collectionFormat decide its serialization and neither is read - joining on a guessed separator would send what the spec never declared.
Internal
- Release builds reuse the vcpkg cache again. Every release had compiled all of its C++ dependencies from source on all three platforms, for two unrelated reasons. build.py --bump-version rewrote "version" in engine/vcpkg.json, which is what the caching workflows key on, so a release minted a cache key nothing had ever written - the field was optional, unread, and outside vcpkg's ABI hash, so it is gone and the bumper refuses to reintroduce it. Separately, Actions caches are ref-scoped and the only workflow writing to the scope a release can read was Linux-only, so macOS and Windows had never had a warm cache at all; cache-warm.yml now resolves dependencies for all three on master, with a guard that fails if the workflows' cache keys drift apart. sccache is deliberately left cold, since a version bump changes the preprocessed text of nearly every translation unit by construction.
- The macOS x64 build no longer times out discovering its own tests. gtest_discover_tests carried a per-test TIMEOUT 60 but left DISCOVERY_TIMEOUT at its 5-second default, which bounds the one --gtest_list_tests run that enumerates the suite at build time. Listing ~1,600 tests through Rosetta, cold, does not fit in five seconds, and the first build to reuse the dependency cache was the first to find out: the x86_64 configure probes that used to warm Rosetta while vcpkg built from source no longer ran, so discovery paid the translation cost itself and the release died at ninja: build stopped after the arm64 half had built and passed. Raised to 150s - it bounds a hang the job timeout already bounds, so generous is the safe direction.
- winget stops deleting the newest versions. The release action's cleanup sorts a single JSON object rather than a list, so -Descending never applies and the tail slice takes the most recent releases - v0.17.0 filed removals against 0.15.0 and 0.16.0 while leaving the broken 0.10.0 in place. Upstream f
0.17.0 15 d’agost del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.17.0 - 2026-08-15
The streaming and data-driven release. Two capabilities that Vayu could describe but not do: a text/event-stream endpoint was unusable - the design path buffered without a cap, blocked a pool thread and reported a status-0 timeout - and a data file was picked in the Run dialog, sent and forgotten, so at the moment someone wrote {{data.email}} nothing in the app knew that column existed. SSE is now a first-class request across all four legs (engine delivery, a live Events tab, scripts over a stream, MCP and codegen), and a collection declares its data contract in a Data tab that the token painter, the completions, the runner and the engine's refusals all read. Two new body modes land beside them - JSON-RPC 2.0 and XML, both enveloped or passed through at the engine chokepoint every client shares. The bulk of the change is new C++ in the engine and new React surface in the app, with the data binder's escaping and auth-ordering fixes concentrated engine-side.
Added
- SSE requests, end to end. POST /execute accepts "stream": true, creates the run row, hands the transfer to a managed consumer worker and answers 202 {runId, eventsUrl} at once. The worker parses frames into a bounded ring; GET /runs/:runId/events relays it with replay+tail, ?lastEventId= resume and the one-watcher claim; the completed trace carries a bounded events node so history restores the timeline. Every stream ends by a rule that names itself - server close, an explicit stop, maxStreamEvents, maxStreamDurationMs or the idle timeout - and nothing on the path is unbounded: the parser caps the frame, the ring caps what it retains, the trace caps what it stores with truthful totalEvents / eventsTruncated markers. The whole-transfer timeout is deliberately absent here, with CURLOPT_LOW_SPEED_LIMIT/_TIME bounding silence instead, so a healthy stream is never killed mid-flight.
- The Events experience. A per-request Event stream toggle (a setting, not a body mode - a stream is a GET as often as a POST, and what it changes is delivery), stored on the request so it survives a tab switch and rides a bulk import. Turning it on arms Accept: text/event-stream and turning it off takes the row back, through the same auto-header primitive the body mode's Content-Type uses. Sending branches to the streaming path, the URL bar's Send becomes Stop, the status band reads "Streaming - N events", and an eighth always-rendered Events tab shows live rows that are replaced by the stored trace when the stream ends - the record being the only copy carrying honest truncation markers.
- Scripts run on a streaming request. The pre-request script runs before the transfer starts, so its pm.request write-back reaches the wire; the post-request script runs once the stream has terminated and reads the bounded list as pm.response.events, with totalEvents and eventsTruncated beside it. Because the route answered 202 long before, script output is stored under the trace's scripts node and read back into the existing Tests and Console panes.
- MCP and codegen reach streams too. run_request takes stream: true, reads the relay under a stated budget and reports which bound stopped it - completed, capReached or budgetExhausted. curl emits -N, HTTPie --stream; fetch, python and powershell state that their stock idiom buffers rather than emitting a command that would hang.
- A collection's data contract, and a Data tab to declare it. collections.data_schema accepted through POST, PUT and /import/apply, validated (unique non-empty columns, capped at 1024 x 256 chars) - with its reader landing in the same change, so resolve_scenario cites the declared columns in the no-data refusal. The app gains the Data tab, a store holding each collection's file path (never its rows), a gated dataFile:read IPC, and a Run dialog that pre-fills from the declared file and diffs it against the schema.
- Schema-aware {{data.*}} at authoring time. The token paints in three states - declared (naming the declar
0.16.0 14 d’agost del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.16.0 - 2026-08-14
The local services and load-test judgement release. Vayu could send in every direction and receive in none, so testing a webhook meant a public tunnel and testing an auth flow meant a live IdP - both now run on loopback listeners the app starts, stops and lists in a new Services drawer, joined by a mock server that replays a collection's imported example responses. On the load-testing side, a run stopped merely reporting numbers and started answering questions: a capacity mode that searches for the knee on its own, per-run thresholds with a pass/fail verdict, a pinned baseline to diff against, per-phase latency histograms over every completion rather than a 1% sample, and a server-vitals overlay charting the target's own metrics on the run's timeline. Around both, the app gained a ⌘K command palette over one shared command registry, and Settings became searchable, with the engine finally declaring what its numbers measure.
Added
- Local webhook inbox. An inbox is an engine-hosted listener that accepts any method on any path, records what arrived - method, path, query, headers, body, timing - and answers a canned response you configure. It closes the one gap air-gapped and corporate users could not work around, since webhook.site and an ngrok tunnel are both outbound. Its tab carries a live capture stream over SSE, a paged capture list that says how much of the retained ring it is showing, and a four-field reply editor (status, delay, headers, body). Body cap, retention and live cadence are settings.
- Built-in OAuth 2.0 mock issuer. Developing against a real identity provider means 2FA prompts, rate limits and "suspicious login" mail; acquire_token always needed a live token endpoint, so auth was the one part of a workspace that could not run offline. A local issuer mints tokens with the lifetime, claims and failure mode you ask for, on its own loopback listener, and is reachable from the Services drawer, the engine API, and three new MCP tools (start_mock_issuer, list_mock_issuers, stop_mock_issuer).
- Mock server over a collection's saved examples. POST /mock/start binds a listener that answers a collection subtree's first saved example on the paths its requests describe, with configurable latency and error injection, and a 404 that names the near-miss instead of stating only that nothing matched. All three path-template spellings - {{petId}}, {petId}, :petId - collapse to one wildcard segment, and specificity decides between two matches so a literal route cannot be shadowed by a wildcard an import happened to write first. Started from the collection header - directly for the common case of serving a collection with nothing set, or through a Mock server options dialog that sets latency and error rate, both start-time so a run pointed at a mock can say which configuration produced its numbers - and managed from the drawer.
- A Services drawer, and a running-services indicator in the Dock. Services are listeners that keep running after you switch tabs, and the shell had no concept for them - the inbox was reachable from one welcome tile and invisible once its tab closed, and the mock issuer had no app surface at all. The fifth drawer view (⇧⌘S) lists inboxes, issuers and mock servers with status, copy-URL, start/stop and delete. Both lists are polled, because the MCP tools and a bare curl reach the same routes; an indicator that only knew what this window started would contradict what it promises.
- Saved example responses have somewhere to live. Imports carried Postman's item.response[] and an OpenAPI operation's responses into a parser that read them and dropped them - no draft field, no wire field, no table, and the loss was not even counted as a skip. A request_examples table owned by its request, CRUD under /requests/:id/examples, an Examples tab, and an example count in the import preview. This is what the mock server serves.
- Capacity-discovery run mode. Finding a service's capacity meant manual bis
0.14.0 1 d’agost del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.14.0 - 2026-08-01
The script editor and state-correctness release. The engine now serves its pm.* surface as TypeScript declarations as well as completions, which turns Monaco's language service on in the script editors - hover documentation, signature help, typo diagnostics with quick fixes, and rename/find-references inside a script. The declarations are generated from the completion table the engine already owns, so the app never carries a second copy to drift from it. Around that, the active environment became real engine state instead of a per-machine localStorage value, and a sustained sweep closed a long tail of renderer bugs that lost edits, served deleted rows from cache, or wrote state nothing ever read.
Added
- A language service in the script editors. A new GET /scripting/types returns the pm.* surface as a .d.ts, generated from the same table that backs GET /scripting/completions - a function's detail is already its signature, so the types are derived rather than hand-maintained. Feeding it to Monaco's TypeScript worker gives hover documentation over an existing call, signature help while typing arguments, red squiggles under pm.response.staus with a "Did you mean 'status'?" quick fix, and rename/find-references/go-to-definition within a script. The worker is configured to match the sandbox rather than a browser - lib: ["es2022"] with no DOM, target: ESNext - so it cannot offer fetch or setTimeout, which do not exist at runtime. The globals the sandbox lacks are declared explicitly with the reason as hover text, and that list is held to the runtime by a test that probes each name in the real script engine.
- Variable names complete inside pm.* accessors. The names were visible in the panel above the editor and had to be retyped by hand into pm.environment.get("..."), where a misremembered one is silent - the accessor just returns undefined. They are now offered in the string argument of every accessor, scoped to what the call can really read: pm.environment.get lists environment variables only, and generators like {{$guid}} appear for pm.variables.replaceIn alone, since that is the only one that interpolates. Both the {{name}} and script lists now also see the active collection's own variables, which previously reached neither editor.
- console levels reach the Console tab. console.log, .info, .warn and .error were indistinguishable in the response pane, because all four were bound to one function that pushed a bare string - the level was destroyed at the QuickJS binding and no styling could have recovered it. Warnings and errors now carry their own colour plus a gutter label, so the distinction is not colour-only.
- One active environment, stored by the engine and restored on launch. environments.is_active was a column nothing enforced, while the choice that actually drove variable resolution lived in localStorage - per-machine, and invisible to the engine storing a column for it. Activating an environment is now a single write (isActive: true), with the previous one deactivated atomically in the same transaction, so no reader ever observes two actives or none. The selection survives a restart and is shared by every client on the same database.
Changed
- Accepting a completion no longer duplicates an existing call. At pm.variables.rep|("$guid"), accepting replaceIn used to leave pm.variables.replaceIn("template")("$guid") - the snippet's own parentheses landing beside arguments the user had already written. When the text after the cursor already opens a call, only the callee is inserted, matching VS Code's completeFunctionCalls behaviour.
- GraphQL schema introspection uses the request's auth. It previously sent header rows and nothing else, so any endpoint whose credentials live in the Auth panel answered 401 and the schema never loaded. Introspection now composes engine-side first, so variables, inherit walked through the collection chain, and OAuth 2.0 all work. The schema cache keys on the whole target rath
0.13.0 31 de juliol del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.13.0 - 2026-07-31
The scripting and composition release. Request preparation - {{variable}} interpolation and inherit-auth resolution - moved into the C++ engine behind a new POST /compose endpoint, ending the era of every client carrying its own copy of the rules, and the scripting sandbox grew the pieces users kept reaching for: dynamic variables, pm.variables.replaceIn, request signing with pm.crypto, and a substantially fuller pm.* surface. The engine also now runs one JavaScript interpreter on every platform - QuickJS-NG 0.16 - where Windows and Linux/macOS previously ran two different ones. The bulk of the change is new C++ in the engine and the deletion of duplicated resolution code in the app.
Added
- Dynamic variables. {{$guid}}, {{$randomUUID}}, {{$timestamp}}, {{$isoTimestamp}} and eleven {{$random*}} generators resolve anywhere {{name}} does - URL, headers, body, form fields - with a fresh value per occurrence, so two {{$guid}} in one body are two ids. The {{ autocomplete offers them under a Dynamic heading. A workspace variable literally named $guid keeps its own value, and an unknown {{$typo}} stays on the wire as written rather than silently emptying the field.
- {{templates}} inside scripts: pm.variables.replaceIn. The same resolver the request fields use, run at call time over a string the script passes in - const id = pm.variables.replaceIn("{{$guid}}"). Because it resolves at call time, a variable the script set a line earlier is visible to it, which {{}} in the URL (resolved before the script starts) can never be. Script source is deliberately never interpolated: a rewrite cannot tell code from a string literal, and splicing variable values into JavaScript would let a variable's value become code.
- Request signing from scripts: pm.crypto and base64 globals. pm.crypto.sha256(data, encoding?) and pm.crypto.hmacSha256(key, data, encoding?) - synchronous, since the sandbox has no event loop for a Promise to settle on - plus standard btoa/atob. Together with the writable pm.request, a pre-request script can now compute and attach an HMAC or webhook signature. Backed by the already-vendored picosha2; OpenSSL is still not linked.
- Engine-owned request composition: POST /compose. The engine resolves {{variables}} (environment > collection chain > globals, enabled only) and walks the collection ancestor chain for inherit auth, returning a fully-resolved payload that POST /execute / POST /runs send byte-for-byte. Composition is pure - nothing is sent, no run row is created - and the execution endpoints never interpolate, so a body that legitimately contains {{...}} survives exactly one resolution. The app's three send paths (Send, load test, History replay) and every MCP execute/load tool now compose through it; MCP checks its host allowlist against the resolved URL before any traffic flows. A shared conformance fixture keeps the app's preview (tab titles, unresolved-token painting) pinned to the engine's semantics, and OAuth 2.0 configs resolve their variables before the token cache key is derived, so two environments differing only through {{vars}} can never share a token.
- A fuller pm.* surface. Every variable scope gained has/unset/clear/toObject, plus the merged read-only pm.variables accessor that resolves across scopes in {{name}}'s own precedence order. Request headers gained get/has/add/upsert/remove (case-insensitive, as HTTP header names are), and responses gained reason() and size(). The script panels link the scripting guide directly.
- Linux installs and updates with the same one-liner as macOS. install.sh now handles Linux end to end - AppImage, desktop entry, icon, and a vayu command when ~/.local/bin is on PATH, all under ~/.local/share/vayu with no sudo - and safely updates an existing install on either platform. On macOS the app can quit itself for an update (the one quit path needing no Automation consent), and the sudo handling was restructured so privileged work is impossible before the pas
0.12.0 30 de juliol del 2026 — 64 bits EXE (NSIS)
Notes de la versió
0.12.0 - 2026-07-30
A correctness and distribution release. Its most consequential fix is one no test could have caught: the Windows engine linked against the Visual C++ redistributable but never shipped it, so on a machine that did not already have that runtime the sidecar could not start at all and the app sat on "Disconnected" with nothing to explain why. Both 0.10.0 and 0.11.0 were affected. Alongside that, the engine now owns id generation outright - a create carrying its own id is refused rather than honoured - Vayu publishes to winget on every release, and the Postman importer stopped losing auth and body detail on the way in.
Added
- Windows installs from winget. winget install athrvk.Vayu is live, and each release now submits its own manifest to microsoft/winget-pkgs automatically once the build matrix is green. A separate Publish to winget (manual) workflow covers what the automatic path cannot - a release that predates the automation, a re-submission after a manifest pull request was closed, or publishing an older tag deliberately - by submitting an existing GitHub release without rebuilding anything.
- A build-time guard on the Windows engine's dependencies. CI reads the built binary's import table and fails if it needs anything that does not ship with Windows itself. It allowlists the operating system rather than denylisting the runtime, so a new third-party dependency is caught the same way the missing runtime would have been.
- A collection can block auth inheritance. The collection Auth tab offers No Auth (blocks inheriting) alongside plain No Auth. The first means "send nothing, and stop here"; the second means "nothing is configured at this level, keep looking upwards". Vayu only had the second, which is why an imported Postman folder set to No Auth still inherited its parent collection's token. The inheritance chain and a request's inherit banner now name the collection that blocked, rather than showing an ancestor the request never actually uses.
Changed
- The engine owns every id, and a create that supplies one is rejected (breaking). POST /collections, /requests and /environments now answer a body carrying an id with a 400 instead of honouring it, so every id in the database comes from the engine. Presence alone is the trigger, null included, because accepting {"id": null} would leave a payload builder believing the field is read. PUT is unchanged except that a body id disagreeing with the path is now a 400 rather than being silently ignored - the path is the identity, and a payload naming two records should not be resolved by guessing. The app strips id before posting, so this is invisible from the UI; it affects anything driving the HTTP API directly.
- The Windows engine is a single self-contained binary. It builds against the static vcpkg triplet with a static MSVC runtime, so nothing is installed beside it - where previous releases shipped a directory of DLLs alongside it, including two GoogleTest libraries that had no business in a user's install directory.
Fixed
- Vayu would not work at all on a Windows machine without the Visual C++ redistributable. The engine imported MSVCP140.dll and VCRUNTIME140.dll, which are not part of a clean Windows installation and were never bundled, so Windows refused to load the binary, the sidecar died the moment it was launched, and the app showed only "Disconnected" - the engine was in the package the whole time and could not start. Every development machine and every CI runner already has that runtime, which is why building and testing the engine never revealed it. The packaging step that should have caught it was wrong in both directions: it copied every DLL it found beside the build output, which swept in the two GoogleTest libraries while missing the runtime entirely, because that never lands there. Removing the dependency rather than adding it to a copy list means there is no longer a list to get wrong.
- A slow import could silently duplicate everything it imp
0.10.0 29 de juliol del 2026 — 64 bits EXE (NSIS)
Notes de la versió
A UI and consistency release. Rebuilt welcome screen as a split launcher, OAuth 2.0 in the collection Auth tab, per-request redirect policy (followRedirects / maxRedirects), ramp-up from a chosen concurrency, two new accent schemes, and broad keyboard operability. Fixes across header bulk-edit, the Cookies tab, restored tabs on cold start, and dark-mode form fields. Almost entirely app-side; the engine is unchanged apart from formatting.

El més popular a API i desenvolupament web

Mostra-ho tot
  1. BrunoAPI i desenvolupament web · Anoop M D
  2. InsomniaAPI i desenvolupament web · Kong
  3. YaakAPI i desenvolupament web · Mountain Loop Labs
  4. RenderDocAPI i desenvolupament web · Baldur Karlsson
  5. Altair GraphQL ClientAPI i desenvolupament web · Samuel Imolorhe
  6. HTTPieAPI i desenvolupament web · HTTPie
  7. ResponsivelyAppAPI i desenvolupament web · Responsively
  8. HurlAPI i desenvolupament web · Orange-OpenSource
  9. SoapUIAPI i desenvolupament web · SmartBear Software
  10. JACK2API i desenvolupament web · jackaudio.org

Etiquetes

Comparteix