Dash0 CLI
npx @buildinternet/releases get dash0-clinpx @buildinternet/releases get dash0-cliAll notable changes to this project will be documented in this file.
The format is based on Keep a Changelog.
github-actions: Add the sync-assets GitHub Action for syncing a directory of Dash0 asset YAML files, deleting assets removed since the last push (#277)
Wraps dash0 apply --since <ref>, deriving <ref> from the triggering event so a workflow does
not have to hand-write github.event.before's corner cases itself.
See .github/actions/sync-assets/README.md for the full reference.
time-series-aggregations: Add the time-series-aggregations command group (alias tsa) and the Dash0TimeSeriesAggregation kind to apply (#281)
The five standard CRUD subcommands (list, get, create, update, delete) are available as
dash0 time-series-aggregations <subcommand> or dash0 tsa <subcommand>, and apply accepts
kind: Dash0TimeSeriesAggregation documents.
Three behaviors differ from the other asset kinds:
metadata.labels["dash0.com/origin"] is mandatory and is the only upsert key. The API rejects an
aggregation without an origin, so there is no server-assigned-id fallback and no plain create: both
create -f and apply -f PUT to the origin, which is create-or-replace. A document without the
label fails before any API call, and during apply's validation phase before any document in the
run is applied.A dash0.com/id in a document body is ignored by the API, so a definition exported with
tsa get -o yaml reapplies as a clean no-op.
slos: Add dash0 slos commands to manage service level objectives (SLOs) as code (#206)
SLO documents use the OpenSLO v1 format (apiVersion: openslo.com/v1, kind: SLO) and are dataset-scoped via --dataset.
The commands support create, list, get, update, and delete, and SLOs can also be managed through dash0 apply.
SLO IDs are assigned by the server, so metadata.labels["dash0.com/origin"] is the upsert key: pin it in version control to make apply idempotent.
slos get and slos delete accept an origin or an ID, slos list -o wide and -o csv expose an ORIGIN column, and slos get prints Origin:.
dashboards, check-rules, views, synthetic-checks, recording-rules, notification-channels, spam-filters, teams, time-series-aggregations: Make update speak with one voice about which asset it addresses (#281)
Every update command resolves the same thing — whether to address the asset named by the
positional argument, the document's dash0.com/origin, or its id — and each one used to answer
it with its own wording. The same mistake produced a different message depending on which asset
type you typed.
The wording is now uniform, and more precise than what it replaces:
no <asset> id given: pass one as an argument, or set the id in the file, and for the kinds that upsert by origin (spam filters, teams, time series aggregations)
no <asset> origin or id given: pass one as an argument, or set metadata.labels["dash0.com/origin"] in the file.Only the message text changed; which asset each invocation resolves to is unchanged.
login: Send client_id on OAuth token revocation requests (#249)
dash0 logout, dash0 login (on re-login), and dash0 config profiles update --oauth=false now
include the profile's client_id when revoking a refresh token, matching the authorization server's
requirement. Without it, revocation silently failed and the old refresh token stayed valid.apply: apply --dry-run changed its output shape, including without --since (#253)
--since renders its deletions in the same listing as creates and updates, so that
listing had to name each row's operation and order the two kinds of row together. Plain
--dry-run shares the renderer and therefore changed too, in three ways:
* and its operation instead of a per-file ordinal:
1. Dashboard "Production Overview" (a1b2c3d4-...) becomes
* Apply Dashboard "Production Overview" (a1b2c3d4-...).--dry-run now emits the documented JSON array of
{path, changes: [{op, kind, name, originOrId}]} instead of the human-readable text,
matching every other command's agent-mode contract.Separately, Dash0Team now renders as Team wherever an asset kind is displayed, so
apply reports Team "Backend Team" created instead of Dash0Team "Backend Team" created. Every other kind already had a human-readable display name; teams fell
through to the raw kind identifier, which also contradicted the --- Team (before)
header their own update diff printed.
Scripts that parsed --dry-run's text output, or grepped for Dash0Team, need
updating. Agent-mode callers should read the JSON rather than parsing text.
apply: Add apply --since <ref> and --force for git-history-based deletion sync (#253)
Deletes assets whose definition existed at <ref> but is no longer present in -f's
current contents, detected by identifier (id or origin), never by file path. Requires
--experimental/-X. --dry-run --since previews the deletion plan, merged with the
existing create/update preview into one per-file listing, and now also resolves deleted
assets' names from git history instead of only showing their id. Agent mode emits
--dry-run's preview as JSON.
Also, while stabilizing this feature ahead of release:
--since now correctly detects an all-deletions run, whether -f's target survives
empty or was removed entirely, instead of failing outright.record: entry is removed, even
though the CRD's own identifier survives via a remaining alert: entry.--force, which keeps its own separate job of skipping confirmation
prompts.--accept-non-ancestor-ref flag accepts a non-ancestor --since ref (e.g. after
a force-push) without also skipping every per-asset deletion confirmation, which
--force alone used to do together.--since-independent bug in apply/check-rules create: a
PrometheusRule CRD with 2+ alerting rules and a dash0.com/id label silently
collapsed to one check rule (the last alert applied overwrote the rest under the
shared id). Each alert now upserts its own derived id. Re-applying an existing
multi-alert CRD leaves an orphaned duplicate at the literal dash0.com/id; delete it
by hand once the new per-alert check rules look correct.apply: Retry a 409 dataset version conflict instead of failing immediately when creating or updating dashboards, check rules, views, recording rules, synthetic checks, or spam filters (#261)
Two dash0 processes (e.g. a CI matrix, or a script running concurrent apply/create/update
commands) writing to the same dataset at once could previously race the dataset's optimistic-concurrency
version check: the losing write got a 409 that nothing retried, and surfaced as a fatal error. The losing
write is now retried with backoff, up to the existing --max-retries/DASH0_MAX_RETRIES budget.check-rules: Merge a PrometheusRule CRD's top-level metadata.annotations into each rule's own annotations, matching the Dash0 Kubernetes operator and Terraform provider (#245)
Previously, a common setting defined once at the top level of a multi-rule PrometheusRule document -
most importantly dash0.com/notification-channel-ids - was silently dropped for any rule that did not
repeat it on its own annotations. A rule's own annotations still take precedence when the same key is
set in both places. This affects check-rules create and check-rules update on PrometheusRule CRD
input, and apply.
auth: Refresh OAuth access tokens for the whole duration of a command, not just at startup (#258)
An OAuth access token lasts 15 minutes, and the CLI resolved it once at startup then reused
it for the rest of the command. Anything that ran longer failed partway through with
authentication failed; check your auth token (status: 401), leaving partial output. Large
exports hit this most often, such as dash0 logs query --from now-7d -o json, along with
bulk dash0 apply -f runs and list over many assets.
The token is now resolved before every request and refreshed as it nears expiry, so a long
command finishes on one dash0 login. A request rejected with 401 is retried once with a
fresh token, which also covers a token revoked elsewhere and clock skew against the
authorization server.
--profile <name> and DASH0_PROFILE never refreshed at all, serving whatever token sat
on disk. They now refresh like the active profile.
Static auth_* tokens do not expire and are still sent unchanged.
teams: teams update now accepts -f <file> with a TeamDefinitionV1Alpha1 document, enabling the export → edit → reapply workflow every other asset kind already supports. (#237)
The imperative --name, --color-from, and --color-to flags keep working for backward compatibility but are now deprecated in favor of -f.
Unlike teams create -f, teams update -f does not create a team on 404 — the target must already exist.config: Setting DASH0_AUTH_TOKEN together with DASH0_API_URL or DASH0_OTLP_URL no longer discards the rest of the active profile, so the profile's dataset reaches the API again. (#240)
That combination used to bypass the active profile wholesale, so requests went out with no
dataset query parameter and the API fell back to default — while dash0 config show kept
reporting the profile's dataset, leaving nothing in the CLI to tell you the two disagreed.
Every setting is now resolved on its own, as docs/commands.md has always documented: an
environment variable overrides only the setting it names, and otlp-url and dataset keep
coming from the profile.
--dataset and DASH0_DATASET are unaffected, and env vars alone still work with no profile
configured at all.
views, synthetic-checks: spec.permissions on views and synthetic checks is now sorted lexicographically (by role, then team, then user) before being displayed or diffed. (#231)
The Dash0 API does not guarantee a stable order for this field, which previously showed up as
spurious changes in views/synthetic-checks update --dry-run and apply diffs, and as
reordered output across repeated get/list -o yaml calls.
metrics: metrics instant's verbose table output now prints Prometheus labels in a stable, sorted order instead of Go's randomized map iteration order. (#231)
Part of an audit into non-deterministic key/array ordering in CLI output (see docs/code-style.md's
"Deterministic output ordering" section for the pattern and the guardrail added against recurrence).
notification-channels: Warn when a Dash0NotificationChannel definition carries a non-empty spec.routing.assets, and omit the API-managed field from exports (#15826)
spec.routing.assets lists the check rules and synthetic checks bound to the channel; the Dash0
API populates it as a back-reference and silently ignores any value supplied on write (existing
bindings are unaffected). apply, notification-channels create, and notification-channels update now warn when a definition carries non-empty assets, pointing at the supported binding
mechanisms (the check rule's dash0.com/notification-channel-ids annotation, the synthetic
check's spec.notifications.channels). notification-channels get and list omit the field
from -o yaml/-o json output, so exported definitions re-apply without warnings.
teams: teams create -f and apply are now idempotent for team YAMLs downloaded from the Dash0 platform UI (#227)
ImportTeam now consults dash0.com/id in metadata.labels as a fallback
upsert key when dash0.com/origin is not set — the API accepts either as
the {originOrId} path segment. UI-downloaded YAMLs carry only id, so
before this fix every create -f and every apply POSTed a new team.
For the cross-environment case (a YAML downloaded from one org, applied to
another), a preflight GET /api/teams/{id} gates the routing: on hit the
CLI PUTs (idempotent update), on miss it falls back to POST (fresh create,
the id in the file becomes advisory). Previously the miss path surfaced as
a "Forbidden: The given team does not belong to your organization" 404.
Origin still wins when both labels are present.
delete: delete --force now treats an already-deleted asset as idempotent success (#217)
Every delete subcommand (dashboards, check-rules, synthetic-checks, views,
recording-rules, notification-channels, spam-filters, teams) and every
remove-shaped variant (members remove, teams remove-members) now
exits 0 and prints a short "already deleted" line to stderr when the target
is already gone and --force was set. The remove variants apply the
check per member so one concurrently-removed member does not fail the
whole --force call. Without --force, a missing target still surfaces
as a non-zero exit with a clean "not found" error. This makes
delete --force safe to invoke from CI/CD and agent-driven pipelines where
the target may have been removed concurrently by another actor.
metrics: metrics instant now honors --profile and DASH0_PROFILE (#221)
Previously the command always resolved its API URL, auth token, and dataset
from the on-disk active profile, silently ignoring the per-invocation profile
selector. It now goes through the same context-carried configuration that
every other API-backed command uses.
skill: Add dash0 skill install and dash0 skill show, which distribute an Agent Skill teaching AI coding agents (Claude Code, Codex, Cursor, GitHub Copilot) this CLI's command surface without spending turns on --help exploration. (#212)
skill install detects the current agent host (Claude Code, Codex, Cursor, or GitHub Copilot) and installs a
SKILL.md plus reference docs into that host's conventional directory in the current project; skill show [topic]
prints the same content to stdout for CI or ephemeral sessions. Neither command calls the Dash0 API or requires
--experimental. In agent mode, a failing command now carries a follow-up hint pointing at dash0 skill install
when the skill isn't installed yet, or at dash0 skill show / dash0 --agent-mode --help when it is — so an
agent that mis-invokes has a concrete next step. Suppress with --no-skill-hint or DASH0_NO_SKILL_HINT=1;
explicit --no-skill-hint=false or DASH0_NO_SKILL_HINT=0 re-enables the hint on demand.teams: teams get -o json and teams get -o yaml now emit the TeamDefinitionV1Alpha1 envelope only, without the enriched members / dashboards / checkRules / syntheticChecks / views / datasets arrays (#200)
Prior versions emitted the enriched GetTeamResponse wrapper ({team, members, dashboards, ...}). The new output is the CRD envelope directly ({apiVersion, kind, metadata, spec}), so dash0 apply -f can round-trip the exported document without post-processing. spec.members renders as email addresses rather than internal user ids.
Scripts that read .team.metadata.labels["dash0.com/id"] or .team.spec.display.name need to drop the .team. prefix — e.g. .metadata.labels["dash0.com/id"], .spec.display.name. Scripts that consumed the enriched arrays (.dashboards[], .members[].spec.display.email, etc.) should use dash0 teams get <id> (the default table output) for a human-readable view, or dash0 teams list-members <id> for programmatic access to the member list.
The dash0 teams * command tree is gated behind --experimental and does not carry a stability guarantee, but this shape change is nevertheless disruptive enough to warrant an explicit callout.teams: Manage teams declaratively via teams create -f and apply -f on Dash0Team YAML (#200)
dash0 --experimental teams create -f <file> accepts a TeamDefinitionV1Alpha1 document. When the document carries a metadata.labels["dash0.com/origin"] label, the CLI upserts by origin (PUT, idempotent); otherwise it creates a new team (POST) and the server assigns id and origin.
dash0 apply recognizes kind: Dash0Team and routes it through the same upsert path, so team definitions round-trip through the standard export-edit-reapply GitOps workflow alongside other assets.
spec.members accepts either email addresses or internal member ids; the server resolves emails during reconciliation and rejects unresolvable ones with a single 400 listing every offender. The CLI renders team membership as emails on teams get, teams list-members, and the apply diff so review artifacts stay legible.
The existing imperative commands (teams create <name>, teams add-members, teams remove-members, teams update) are preserved and now accept emails or ids for member arguments.check-rules: Name check rules imported from a PrometheusRule CRD as <group name> - <alert name>, matching the Dash0 Kubernetes operator and Terraform provider (#182)
Previously the CLI named such check rules after the alert only, so the same CRD produced a different name than the operator and Terraform provider.
This affects check-rules create, check-rules update, and apply.
Check rule identity for upsert is the dash0.com/id / id, not the name, so for definitions that pin an identifier this is a non-destructive in-place rename surfaced as a one-line diff on the next apply.build: Add Nix flake packaging so the CLI can be installed and run on Nix and NixOS (#174)
The flake builds the CLI with buildGoModule, installs Bash, Zsh, and Fish
completions, and exposes nix run, nix profile install, an overlays.default
for NixOS and Home Manager, and a nix develop shell. Non-flake default.nix
and shell.nix shims are provided for systems without flakes enabled. A
homeManagerModules.default declares profiles under ~/.dash0: static tokens
are read from authTokenFile at activation time and OAuth profiles are seeded
for dash0 login, with runtime-acquired tokens preserved across rebuilds.
A pre-built binary is published to a Nix User Repository for a compile-free
install on small or non-x86_64 machines.homebrew: Resume publishing the Homebrew cask to the dedicated tap on every release (#175)
Tagged releases failed to update Casks/dash0.rb in dash0hq/homebrew-dash0-cli
because the release pipeline could not write to the tap repository, leaving cask
users pinned to a stale version. The cask is now published again on each release,
so brew upgrade --cask dash0 tracks the latest version.homebrew: Fix brew install --cask dash0hq/dash0-cli/dash0 failing on Linux (#172)
The generated Homebrew cask ran an unconditional postflight hook invoking the
macOS-only /usr/bin/xattr to strip the Gatekeeper quarantine attribute. On Linux
that tool does not exist, so the install aborted at the postflight step even though
the cask shipped correct Linux binaries. The hook is now guarded with if OS.mac?.failed-checks: Add dash0 failed-checks query command to query active and historical alerting issues (#92)
Supports filtering by --status critical,degraded, --active (unresolved only),
and generic --filter expressions using the same syntax as logs query and spans query.
Output formats: table (with semantic coloring for status), json, csv.
Customize the displayed columns with --column; any issue label (such as priority or owner)
can be used directly as a column name.
The list and ls aliases are available for backwards compatibility.spam-filters: Accept group-prefixed apiVersion values (e.g. operator.dash0.com/v1alpha1, dash0.com/v1alpha1) in spam filter YAML input (#169)
The CLI rejected spam filter documents exported from the Dash0 Kubernetes operator because they
carry a group-prefixed apiVersion. The CLI now normalizes these to the bare version before
dispatching, so operator-exported and canonical-form YAML files work with create, update, and apply.auth: Add dash0 login and dash0 logout for browser-based OAuth 2.0 + PKCE authentication (#27)
Profiles now have an explicit auth mode: static (long-lived auth_* token) or OAuth (browser flow).
Mark a new profile as OAuth at creation time with dash0 config profiles create <name> --oauth --api-url <url>,
then run dash0 login to obtain access and refresh tokens.
Access tokens are refreshed transparently before they expire; dash0 logout revokes them best-effort
and clears the tokens from the profile while keeping the profile shell for re-login.
Switch a profile between static and OAuth at any time with dash0 config profiles update <name> --oauth[=true|=false]
(the transition is destructive and prompts for confirmation unless --force is passed).
dash0 config profiles list gains an AUTH column showing the auth mode and remaining token lifetime,
and dash0 config show annotates the Auth Token: line with OAuth state.
dash0 login requires an interactive terminal — agent mode and non-TTY environments still use static tokens
via DASH0_AUTH_TOKEN or dash0 config profiles create --auth-token.
dash0 logout requires --force when invoked in agent mode (or when auto-detected via env vars like
CLAUDE_CODE), so an AI agent cannot silently revoke a profile's refresh token.
Telemetry send commands (dash0 logs send, dash0 spans send) refuse upfront when the active profile
is OAuth-typed, because the Dash0 OTLP ingress does not (yet) accept OAuth access tokens — only static
auth_* tokens. The error names the workarounds: pass --auth-token auth_<...> for the invocation,
set DASH0_AUTH_TOKEN, or convert the profile with dash0 config profiles update <name> --oauth=false.
Older dash0 CLI binaries from before OAuth support shipped (e.g. v1.12.0) do not understand
OAuth-typed profiles. dash0 config show and dash0 config profiles list silently render the
access token as if it were a static one (no (OAuth, ...) annotation), and any command that calls
the API fails with auth token must start with 'auth_' when the api-client library rejects the
dash0_at_* prefix. If you have multiple dash0 binaries installed (for example a homebrew-installed
dash0 alongside a development build) make sure every binary reading the profile is from this
release or later. Static-token profiles are unaffected.
otlp: Add dash0 otlp proxy, a long-running local OTLP forwarder that accepts OTLP/HTTP and OTLP/gRPC traffic and forwards every batch to Dash0 using the active profile's credentials. (#159)
The proxy binds 127.0.0.1:4318 (OTLP/HTTP) and 127.0.0.1:4317 (OTLP/gRPC) by default — an OpenTelemetry SDK at default endpoint configuration connects with no environment variable change.
It is gated behind -X (experimental) and is not intended as a replacement for the OpenTelemetry Collector.
See docs/commands.md for the full reference including the agent-mode event schema and failure-mode classification.
logs, spans, traces: Add --precision <adaptive|disabled> to logs query and spans query to select the API sampling mode for the request. traces get always disables adaptive sampling so the complete trace is returned. (#167)
Without the flag the API defaults to adaptive sampling, which samples telemetry data during query execution to keep queries fast on large datasets while returning statistically representative results.
Pass --precision disabled for the API equivalent of the Precision toggle in the Dash0 UI: every matching record is returned, at the cost of higher query latency on wide time ranges.
Use this for narrow lookups (e.g. test.id is <uuid>, trace.id is <hex>) that must be deterministic.
traces get always disables adaptive sampling — retrieving a trace must return every span in the trace regardless of query window, so the flag is not exposed on that command.
homebrew: Homebrew distribution is moving to a dedicated tap at dash0hq/homebrew-dash0-cli and switching from a formula to a cask. (#82, #162)
Starting with the next release, new users install with:
brew install --cask dash0hq/dash0-cli/dash0 — no brew tap, no brew trust.
Existing tap users will see a deprecation warning on brew upgrade dash0
pointing at the new install path. The formula-to-cask switch follows
Homebrew's convention for pre-built binary CLIs and aligns with
goreleaser's deprecation of its brews: configuration. See
docs/brew-tap-migration-2026-06.md for the full migration guide.
notification-channels: surface the Dash0 web app deep link in notification-channels list and notification-channels get (#147)
The list table and CSV output now include a URL column with a direct link
to the channel in the Dash0 web app. The get table output prints the same
URL as a new URL: field.config: Rename DASH0_RETRY_COUNT to DASH0_MAX_RETRIES and add --max-retries global flag (#141)
The environment variable DASH0_RETRY_COUNT has been renamed to DASH0_MAX_RETRIES for consistency with the Terraform provider.
A new --max-retries global flag is now available on all commands as an alternative to the environment variable.
Resolution order: --max-retries flag, then DASH0_MAX_RETRIES env var, then default (3).send-log-event action: Fix send-log-event action ignoring connection inputs when a profile already exists (#143)
When a profile already existed (e.g., from the setup action), the action skipped profile creation
and ignored any otlp-url, auth-token, or dataset inputs. The action now updates the existing
profile with the provided values.apply: Accept Dash0NotificationChannel and recording-rule PrometheusRule documents in dash0 apply (#137)
dash0 apply now accepts Dash0NotificationChannel documents and dispatches them to the
organization-level notification-channels endpoint without a dataset query parameter.
PrometheusRule CRDs containing recording rules (entries with record:) are now dispatched to the
recording-rule endpoint as a single PrometheusRule CRD; mixed CRDs that contain both alerting and
recording rules are dispatched to both endpoints in one apply. Previously, recording rules in a
PrometheusRule CRD were silently dropped during apply. A CRD with no rules of either kind now
fails validation up front with a clear error. The unified diff that apply prints for notification
channels and recording rules now strips server-managed fields (dash0.com/created-at,
dash0.com/updated-at, and similar) so the second apply on unchanged input renders as
"no changes".
spam-filters: Accept v1alpha2 schema in spam-filters create/update/get and in apply (#136)
The CLI now detects the apiVersion on spam filter documents (v1alpha1 or v1alpha2) and routes to the
matching API endpoint. v1alpha2 uses spec.context (a single signal type) instead of spec.contexts
(an array). A missing apiVersion defaults to v1alpha1. An unknown value is rejected with a clear
error listing the supported versions. dash0 apply accepts Dash0SpamFilter documents in either
schema and rejects unknown apiVersion values during validation, before any document is applied.
client: include the parsed server message, HTTP status, and trace ID in every API error printed by the CLI (#139)
Errors now show the human-readable message extracted from the Dash0 API response (instead of dumping the raw JSON body).
404 responses now also surface the HTTP status and trace ID so support can correlate to server-side logs.spam-filters: Fix spam filter FilterCriteria format in fixtures and tests to match the Dash0 API schema (#134)
The filter criteria now use the correct flat format with operator and value fields instead of the nested stringValue format.spam-filters: Add spam-filters command with list, get, create, update, and delete subcommands (#132)
Manage dataset-scoped spam filters via dash0 spam-filters <subcommand>.
Supports file-based input (-f), dry-run validation, and all standard output formats (table, wide, json, yaml, csv).recording-rules: Fix recording rules create and update not passing the dataset as a query parameter (#130)
The --dataset flag and profile dataset were silently ignored for recording-rules create and recording-rules update.
Updated dash0-api-client-go to v1.11.1 which passes the dataset as a query parameter.recording-rules: Add recording rules commands (create, list, get, update, delete) for managing Prometheus recording rules via the PrometheusRule CRD format. (#126)config: Add --profile global flag and DASH0_PROFILE environment variable to select a profile per invocation. (#127)
The selector overrides the active profile on disk for the current invocation
without modifying ~/.dash0/. Precedence is --profile flag → DASH0_PROFILE
→ the active profile. A non-existent profile fails before any API call with a
message listing the available profiles. Passing an empty value falls through
to the next step. config show annotates the Profile: line with the source
when a selector is in effect.api: Add experimental api command for raw HTTP calls to the Dash0 API. (#122)
The dash0 -X api command performs a raw HTTP request against any Dash0 API endpoint,
reusing the active profile's API URL, auth token, and (by default) dataset.
It is useful for endpoints that do not yet have a dedicated subcommand.metrics: Rework metrics instant with new flags and output formats (#45)
Add --promql flag (replacing the deprecated --query), --filter for PromQL label matcher generation,
--from (replacing the deprecated --time), -o csv output format, --skip-header, and --column for
columnar table and CSV output. The timestamp and value columns are always included automatically.
Deprecated flags (--query, --time) remain functional for backwards compatibility.
logs, spans, traces: Promote logs query, spans query, spans send, and traces get commands to stable (#124)
These commands no longer require the --experimental (-X) flag.
notification-channels: Add notification-channels command for managing notification channels (list, get, create, update, delete) (#119)
Notification channels are organization-level resources (no --dataset flag).
The command uses CRD-enveloped NotificationChannelDefinition types with file-based input.
All subcommands are experimental and require the -X flag.check-rules: check-rules update now accepts PrometheusRule CRD files (#110)
Previously, check-rules update -f failed with "no check rule ID provided" when given a PrometheusRule CRD file,
because it did not detect the kind and route to the PrometheusRule parser. Both apply and check-rules create
already handled this correctly.
dashboards: dashboards update now accepts PersesDashboard CRD files (#111)
Previously, dashboards update -f did not detect PersesDashboard CRD files, so the CRD-specific conversion
(v1alpha1/v1alpha2 normalization, ID extraction from labels, annotation mapping) was skipped.
Both apply and dashboards create already handled this correctly.
agent-mode: Add agent mode for AI coding agents (#68)
When active, agent mode defaults output to JSON, returns errors as JSON on
stderr, emits --help as structured JSON, skips confirmation prompts, and
disables colored output. Agent mode is activated via --agent-mode, the
DASH0_AGENT_MODE environment variable, or auto-detection of known AI agent
environment variables (CLAUDE_CODE, MCP_SESSION_ID, CURSOR_SESSION_ID, etc.).dashboards: Clear dashboard ID from the request body before update calls to avoid server-side rejection (#101)
When updating a dashboard whose user-defined ID is a UUID, the server rejects the request if the
same ID appears in both the URL path parameter and the request body. The CLI now strips the ID from
the body before sending the update, since it is already passed as the URL path parameter.
dashboards: Fix PersesDashboard annotations (folder-path, sharing, source) being silently dropped during conversion (#103)
User-settable annotations (dash0.com/folder-path, dash0.com/sharing, dash0.com/source) on PersesDashboard CRDs
were not carried over when converting to a Dashboard definition, affecting both apply and dashboards create.
query: --filter now accepts JSON filter criteria copied from the Dash0 UI (#96)
The --filter flag on logs query and spans query now accepts JSON arrays and objects
as produced by the Dash0 UI "copy filter criteria" feature, in addition to the
existing text-based filter syntax. JSON and text filters can be mixed freely.apply: Preserve user-settable annotations and permissions on asset round-trips (#99)
dash0.com/folder-path, dash0.com/source, and dash0.com/sharing annotations were silently dropped during apply, <asset> create and <asset> update.
spec.permissions on views and synthetic checks was also stripped.apply: Migrate asset create/update from Import APIs to standard CRUD APIs (#90)
The apply command and individual asset create/update subcommands now use the standard
Create and Update APIs instead of the Import APIs, which are intended for one-time migrations.apply: When an asset definition includes a user-defined ID, apply now always upserts, making repeated applies idempotent and preventing duplicate assets from being created. (#94)output: The update and apply commands now show a unified diff of changes (#66)
dashboards: <asset> list -o yaml and -o json now output full asset definitions instead of summary list items (#67)
YAML output is a multi-document stream (separated by ---) that can be piped directly to dash0 apply -f -.
JSON output is an array of full asset definitions.
This applies to all four asset types: dashboards, check-rules, views, and synthetic-checks.
dashboards: Accept PersesDashboard CRD files in apply and dashboards create (#85)
PersesDashboard CRDs (perses.dev/v1alpha1 and perses.dev/v1alpha2) are now accepted as input.logs, spans, traces: Add explorer deep link URL as the first line of output for logs query, spans query, and traces get (#71)
The URL is printed after the table output and links to the corresponding Dash0 explorer view.synthetic-checks, views: Display the human-readable name instead of the CRD name for synthetic checks and views (#80)
The get, create, and update commands for synthetic checks and views now read from
spec.display.name instead of metadata.name, consistent with dashboards.errors: Include API response body in error messages when the backend does not return a structured error (#75)
Previously, errors like 400 Bad Request only showed the HTTP status code and trace ID.
Now, the full response body is displayed so that users can see the reason for the failure.
dashboards: Make the <id> argument of dash0 <asset> update optional (#76)
When the <id> argument is omitted, the ID is extracted from the file content.
This applies to all asset types: dashboards, check rules, synthetic checks, and views.
dashboards: Fix dashboards update overwriting dash0Extensions.id with the origin string (#77)
Unify ID and name extraction between apply and per-asset CRUD commands by
delegating to shared Extract* functions in internal/asset/.
dashboards: Stop force-setting origin in asset update commands (#78)
The synthetic-checks update, views update, and check-rules update commands
were force-setting the origin to "dash0-cli", causing 400 errors when updating
assets originally created with a different origin.
views: Fix view deeplink URLs to use the correct path for each view type (#72)
Previously, all view deeplinks used /goto/logs regardless of view type.
Now each view type maps to its correct deeplink path (e.g., /goto/traces/explorer for span views, /goto/metrics/explorer for metric views).
The views list output also includes a new TYPE column.teams: Add experimental team and member management commands (#47)
New teams commands: list, get, create, update, delete, add-members, remove-members.
New members commands: list, invite, remove.
All commands require the --experimental (-X) flag.