v2.6.0
Summary
This release moves the CLI to API version 2026-09-01 and brings delivery groups to the command line: per-group rate limits and overrides on destinations, standalone or inline on a connection, plus a --delivery-group filter across events, request events, metrics, and the MCP tools.
Alongside that is a long list of fixes sharing one shape — the CLI reported success while doing something other than what you asked. listen connected but never said so when its output was piped. gateway metrics accepted filters the endpoint silently ignores and returned unfiltered totals formatted as if filtered. gateway transformation run printed a green tick whether your code worked or threw. hookdeck login opened a browser and hung forever on a machine with no terminal.
Project mode is now project type, following the API. Existing config files keep working in both directions.
New features
-
Delivery groups on destinations. Rate limits now travel through
config.delivery_policy, and you can set per-group limits and overrides directly:hookdeck gateway destination create --name orders \ --delivery-group-key '$.body.tenant_id' \ --delivery-group-rate 100 --delivery-group-rate-period minute \ --delivery-group-overrides '{"tenant_a": {"rate": 500}}'
The same options exist inline when creating a connection, prefixed
--destination-delivery-group-*, beside the existing--destination-rate-limit*. -
--delivery-groupfilter ongateway events list,gateway requests list,gateway metrics, and the corresponding MCP tools. -
gateway request eventsgains the full event filter set —--source-id,--destination-id,--connection-id,--status,--attempts,--response-status,--error-code,--issue-id,--body,--headers,--path,--parsed-query, the four date-bound pairs,--order-byand--dir. Previously it offered five flags while the endpoint honoured twenty; the rest were silently dropped. -
NO_COLORis now honoured across the CLI, alongside the existing--color off. -
API version
2026-09-01. The cached source-type list is keyed by API version, so upgrading no longer reuses a cache built against2025-07-01.
Fixes
listen
-
listenconnects but never prints "Connected". The readiness line was attached to the terminal spinner, so anywhere the spinner could not run — output piped to a file,--color off, no TTY — the CLI connected and forwarded traffic while never confirming it. Reported by a user who concluded the websocket had failed; the tunnel was live the whole time. (#376) -
listenlooked connected before it was. In the default interactive mode the full UI rendered immediately with a blank status bar, so a connection that was still being established — or had failed — was indistinguishable from a live one. The status bar now always reports state:Connecting…,Connected., orConnection failed: <reason>. (#399) -
listensaid it gave up but not why. The dial error was debug-only. (#383) -
Compact mode printed a bare
Listening onwith the summary missing. Compact is the automatic fallback when there is no TTY, so this was the line most CI logs carried. (#402) -
Terminal hyperlinks were emitted only where they cannot render — escape sequences went into piped and redirected output and were withheld from real terminals, and
--color offdid not suppress them. (#403) -
--color offwas ignored by the interactive UI. (#404)
Sign-in
-
hookdeck loginopened a browser and hung indefinitely when there was no terminal. Any CI job, Dockerfile,nohupscript or coding agent running it would spawn a browser process and block. It now fails immediately, naminghookdeck ci --api-key,hookdeck login --cli-keyandHOOKDECK_API_KEY. The same gap existed on the guest-upgrade path. (#400, #373) -
The sign-in URL is now always printed before the spinner. It was previously shown only if launching the browser returned an error — but a browser that fails after launching is undetectable, so on WSL, in containers and under VS Code Remote you got a spinner and no link.
-
hookdeck login -iwith no terminal leaked a rawoperation not supported by device. (#401) -
Ctrl-C could be dropped during interactive login, leaving the terminal with echo disabled. (#384)
-
An expired or rejected key now tells you what to do, rather than
unexpected http status code: 401, raw response body: Unauthorized.
Metrics
-
gateway metricsaccepted filters the endpoint ignores. Passing--connection-idtometrics attempts, or--source-idtometrics transformations, was accepted without complaint — but the API silently drops unsupported filters rather than rejecting them, so the CLI printed unfiltered totals formatted exactly like a filtered result. Nothing on screen distinguished the two. Ten such pairs existed on the CLI and 22 on the MCP tools. (#382) -
--measures pendingonly worked if you also passed--granularity. Otherwise it was routed to an endpoint that does not accept the measure and returned a raw 422. -
--measures queue_depthnever worked. It was advertised in--helpbut is not a value the endpoint accepts. -
--dimensionsand--statusadvertised one shared vocabulary across all four subcommands, and it was wrong on three. Following the help produced a 422. Request events areACCEPTED/REJECTED, attempts areSUCCESSFUL/FAILED, events carry the full six-value set. -
The metrics example in
gateway --helpwas missing the required--measures, so copying it verbatim failed.
Destinations and connections
-
--confighad its path overwritten on CLI destinations.--config '{"path":"/webhooks"}'created a destination at/, because--cli-pathcarries a/default and an unset flag beat the value you supplied. (#392) -
gateway connection upsertreset an existing CLI destination's path to/on any upsert that omitted--destination-cli-path. -
destination updateandupsertsilently dropped--url(and--cli-path) whenever--typewas omitted — which is the normal way to run an update, since the type is already stored. (#406) -
Negative rate limits are rejected.
--rate-limit -1was accepted and sent.
Transformations
gateway transformation runreported success for every failure. A thrown exception, invalid JavaScript, or an unknown--idall printed✔ Transformation run completedand exited 0, with--output jsonreturning{}. Console output was never surfaced. Testing a transformation before shipping it is the command's purpose, and it could not tell you the code was broken. It now exits non-zero and shows the error, and console output appears for successful runs too — a handler that logs an error and still returns is the case you are most likely to be debugging. (#410) Note that errors from other commands still print to stdout rather than stderr, so--output json | jqcan still receive prose on the JSON channel elsewhere. (#394)
MCP
-
Arguments an action does not support are now refused rather than sent and silently dropped by the API.
-
The metrics tool advertised measures, dimensions and status values that most routes reject. All three are now accurate per action and derived from the same source as the CLI's, so the two cannot drift.
-
meta.active_project_namewas always empty for project-scoped credentials, so a client could only show a baretm_…id. (#405) -
API validation errors surfaced as raw JSON with internal fields, burying the useful message.
-
ignored_eventsdropped pagination.
Improvements / behavior changes
-
Project
modeis now projecttype, following the API's rename:event_gateway,console,outpost(inbound and outbound both fold intoevent_gateway). This is internal vocabulary —--output jsonstill emitsgateway,outpost,consoleexactly as before, so scripts reading it need no change. -
Config stays compatible in both directions.
project_typeis written as the display label (Gateway) that v2.5.0 understands, and a type this version does not recognise is preserved rather than blanked.One caveat, since it is not a config-format property: v2.5.0 reads only
team_modefrom the auth response and ignoresteam_type. The two versions coexist because they call different API versions, so the older prefix continues to serveteam_mode. -
--measuresis now a required flag on the metrics subcommands. It was always required by the API; the CLI now says so up front instead of letting the request fail. -
Dimensions are validated per metrics route. A dimension the endpoint does not group by is refused with a message naming the ones it does, instead of being sent and rejected.
-
--configtakes precedence over the individual destination config flags, which are ignored when it is present. Set the field in the JSON rather than combining the two. (#415) -
--helpfor each auth path now states which kind of key it accepts:hookdeck login --cli-keytakes a CLI key,hookdeck ci --api-keytakes a project API key. Organization API keys are not accepted by either.
Internal / reliability / infrastructure
- The supported measure, dimension, filter and status vocabularies for every metrics route are now one shared table used by both the CLI and the MCP server, rather than separate per-layer lists.
Full Changelog: v2.5.0...v2.6.0