npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tsuga/cli

v1.40.0

Published

Tsuga CLI - manage resources from the command line

Readme

@tsuga/cli

Command-line interface for managing Tsuga resources.

Installation

npm install -g @tsuga/cli
tsuga --help

Updating

Update to the latest published version:

tsuga self-update

This runs npm install -g @tsuga/cli@latest. The CLI also checks for new versions once a day and prints a notice when one is available.

Shell completion

Tab-complete commands and flags in bash, zsh, or fish.

For bash and zsh, add the matching line to your shell startup file:

# ~/.bashrc
eval "$(tsuga --completions bash)"

# ~/.zshrc
eval "$(tsuga --completions zsh)"

Then open a new shell (or source the file).

For fish, write the script to your completions directory:

tsuga --completions fish > ~/.config/fish/completions/tsuga.fish

Fish loads it automatically in new shells.

Authentication

All authentication lives under tsuga auth.

tsuga auth status reads the saved credential locally. To ask Tsuga which credential the CLI actually authenticates as, and what it is allowed to do:

tsuga auth whoami
tsuga auth whoami -o json

Log in as a user (recommended)

For interactive use, log in as a user with a browser authorization flow:

# Opens your browser to an authorization URL, or prints the URL if it can't be opened.
tsuga auth login

# Print the saved user access token
tsuga auth token

# Show the current authentication method, and when the session expires or expired
tsuga auth status

# Ask Tsuga who this CLI authenticates as
tsuga auth whoami

# Clear the saved user session
tsuga auth logout

After tsuga auth login, commands work without an Operation API key.

Sessions renew themselves: the login also saves a refresh token, and the CLI exchanges it for a new access token when the current one is within five minutes of expiry. You log in again when the refresh token expires, when it is revoked, or when the session has no refresh token.

Operation API key

For non-interactive use (CI, scripts), authenticate with an Operation API key. Generate one from your Tsuga account settings, then save it once:

tsuga auth operation-key <OPERATION_API_KEY>

This writes the operation API key to $XDG_CONFIG_HOME/tsuga/config.json, or ~/.config/tsuga/config.json when XDG_CONFIG_HOME is unset. Alternatively, set it per-session without saving:

export TSUGA_OPERATION_API_KEY=<OPERATION_API_KEY>

A TSUGA_OPERATION_API_KEY env var overrides the saved credential for that one invocation.

Configuration

Show current configuration (includes defaults):

tsuga config

Defaults

Commands have built-in defaults so you can omit common flags:

| Flag | Default | | --------------- | ------- | | --from | -30m | | --to | now | | --query | * | | --max-results | 100 |

Override defaults persistently. The value is given with --value:

tsuga config set default from --value=-1h
tsuga config set default query --value 'level:ERROR'

Current defaults are listed by tsuga config (custom overrides marked with *).

Reset all custom defaults:

tsuga config reset defaults

Clear a single default by setting it to an empty value:

tsuga config set default cluster --value ''

Clusters

If your tenant has multiple clusters, list them:

tsuga clusters list

Pick the cluster you want to use by default via the defaults mechanism:

tsuga config set default cluster --value <CLUSTER_ID>

Override per-command without persisting:

# Environment variable
export TSUGA_CLUSTER_ID=<CLUSTER_ID>

# CLI flag (highest priority)
tsuga --cluster <CLUSTER_ID> logs search

Priority order: --cluster flag → TSUGA_CLUSTER_ID env var → defaults.cluster. If unset, the backend falls back to the first cluster.

Usage

Most resources follow the same CRUD pattern:

tsuga <RESOURCE> list
tsuga <RESOURCE> get <ID>
tsuga <RESOURCE> create -f payload.json
tsuga <RESOURCE> update <ID> -f payload.json
tsuga <RESOURCE> delete <ID>

Read-only resources (for example services) support only:

tsuga services list
tsuga services get <ID>

You can also pass JSON inline with -d:

tsuga teams create -d '{"name": "Platform", "visibility": "public"}'

Pagination

list returns the first 100 items by default. Paginated resources accept --limit (up to 1000) and --offset:

tsuga monitors list --limit 500
tsuga monitors list --limit 500 --offset 500

When a page leaves items behind, the CLI prints a notice to stderr and leaves stdout as pure JSON, so | jq and -o csv are unaffected:

Showing 100 of 4212 (offset 0). Use --limit (max 1000) and --offset 100 for the next page.

For resources with server-side filters, narrowing the query beats paging through everything.

Explaining a call with --rationale

Every command accepts an optional --rationale flag to record why it is being run. It does not change the result; the text is sent as a request header on any API call the command makes, and recorded in the backend request log, which is useful for understanding agent behavior.

tsuga logs patterns --rationale "exploring telemetry to investigate prod outage"

--rationale, --cluster and --operation-api-key are shared flags: they may be given before or after the subcommand, and are inherited by every subcommand.

Available resources

cloud-resources, dashboard-folders, dashboards, ingestion-api-keys, investigations, monitors, notification-integrations, notification-rules, notification-silences, public-tokens, quality-reports, retention-policies, log-routes, services, slos, tag-policies, teams

Notes:

  • ingestion-api-keys does not support get <ID>.
  • services is read-only (list, get).
  • cloud-resources and quality-reports are read-only and only support list.
  • For quality-reports list, pass --cluster <CLUSTER_ID> (or set TSUGA_CLUSTER_ID / saved default) when the org has more than one cluster.
  • Pass --team <TEAM_NAME> to quality-reports list to scope the response to a single team by name (omits cluster-wide global rows).
  • investigations is beta: it requires an operation API key with the investigations permission and the API may change.
  • public-tokens manages the RUM public tokens configured in browser and mobile SDKs. It requires an operation API key with the RUM public tokens (rum-public-token) permission.
tsuga public-tokens create --generate-skeleton > app.json
# edit app.json
tsuga public-tokens create -f app.json | jq -r .token
tsuga public-tokens list | jq -r '.[0].token'

Generating a request skeleton

Any create or update command accepts --generate-skeleton to print a JSON template of the expected request body:

tsuga monitors create --generate-skeleton
tsuga notification-rules update abc-123 --generate-skeleton

Pipe the output to a file, fill it in, then pass it back with -f:

tsuga monitors create --generate-skeleton > monitor.json
# edit monitor.json
tsuga monitors create -f monitor.json

Examples

# List all monitors
tsuga monitors list

# Get a specific dashboard
tsuga dashboards get abc-123

# List dashboards filtered by owner
tsuga dashboards list -d '{"filters":{"owners":{"values":["team-1","team-2"]}}}'

# Get a specific service
tsuga services get abc-123

# Create a notification rule from a file
tsuga notification-rules create -f rule.json

# Update a log route
tsuga log-routes update abc-123 -d '{"name": "Updated log route"}'

# Delete a retention policy
tsuga retention-policies delete abc-123

Telemetry

Time formats

Use an equals sign for negative offsets, such as --from=-1h.

--from and --to accept any of:

| Format | Example | | ------------ | ---------------------------- | | Relative | -30m, -1h, -7d, -30s | | Now | now | | Unix seconds | 1704067200 | | ISO 8601 | 2024-01-01T00:00:00Z |

Search logs

tsuga logs search --from=-1h --query 'level:ERROR'
tsuga logs search --from 1704067200 --to 1704153600 --query 'service:api'

By default, the full JSON response is printed. Use --fields to project specific dot-paths from each log, and -o tsv|csv for tabular output:

# JSON projected to selected fields (preserves the {logs: [...]} envelope and nesting)
tsuga logs search --from=-10m \
  --fields timestamp,level,message,context.k8s.pod.name

# TSV with default columns: timestamp, level, message
tsuga logs search --from=-10m --query 'level:ERROR' -o tsv

# CSV with custom columns
tsuga logs search --from=-10m -o csv \
  --fields timestamp,level,message,context.k8s.pod.name

Log attributes

tsuga logs attributes --from=-1h

Log patterns

# Group recent logs into patterns
tsuga logs patterns --from=-1h --query 'level:ERROR'

# List new error patterns observed in the time range
tsuga logs new-error-patterns --from=-24h --team my-team --service api --env prod

# List error patterns whose volume increased for a team
tsuga logs error-pattern-increases --from=-24h --team my-team --env prod

Search traces

tsuga traces search --from=-30m --query 'span_name:GET'

Search RUM events

Prefix query fields with the stream they belong to (measurements., events., or exceptions.), and filter on one stream per query. A query without a prefixed field, including the default *, searches the events stream:

tsuga rum search --from=-1h --query 'events.view.name:/checkout'
tsuga rum search --from=-1h --query 'exceptions.exception.type:*' --max-results 20

RUM attributes

Lists every RUM attribute you can query:

tsuga rum attributes

Both RUM commands require an operation API key with the RUM events (rum) read permission.

Summarize a trace

Aggregates groups of similar spans into synthetic summary spans (marked with spanAttributes.aggregation.is_summary) for a compact view of large traces:

tsuga traces summarize --trace-id 78c99c5bb1e4a30297fa134b9dbec64f --from=-30m

Trace latency summary

Summarizes where wall-clock time is spent in a trace: each slice of the timeline is attributed to the services with active leaf spans, with per-service totals:

tsuga traces latency-summary --trace-id 78c99c5bb1e4a30297fa134b9dbec64f --from=-30m

# Per-service totals only, without the range timeline
tsuga traces latency-summary --trace-id 78c99c5bb1e4a30297fa134b9dbec64f --from=-30m --no-ranges

# Collapse timeline ranges shorter than 50ms (0 disables collapsing)
tsuga traces latency-summary --trace-id 78c99c5bb1e4a30297fa134b9dbec64f --from=-30m --min-range-duration-ms 50

Contrast sets

Compares a target group of spans against a baseline and returns the attribute values that are over-represented in the target — what those spans have in common that the baseline ones do not. Each group carries its own filter and time range.

Filters are written in TQL, the same query language as --query elsewhere: terms are ANDed by whitespace, span_attributes.* addresses span attributes, and duration is in milliseconds. Run tsuga docs get explore/query-syntax for the full syntax.

tsuga traces contrast-sets --generate-skeleton > groups.json
tsuga traces contrast-sets -f groups.json

Time ranges are Unix seconds, and unlike --from / --to they are not resolved from relative strings — the body takes numbers. The skeleton and the examples below carry a fixed window that is long past, so substitute your own:

TO=$(date +%s)
FROM=$((TO - 3600))

Erroring spans against healthy ones, for one service in one window:

cat > groups.json <<EOF
{
  "targetGroup":   {"filter": "context.service.name:checkout status_code:error", "timeRange": {"from": $FROM, "to": $TO}},
  "baselineGroup": {"filter": "context.service.name:checkout NOT status_code:error", "timeRange": {"from": $FROM, "to": $TO}}
}
EOF
tsuga traces contrast-sets -f groups.json

Slow spans against normal-latency ones:

tsuga traces contrast-sets -d '{
  "targetGroup":   {"filter": "context.service.name:checkout duration:>2000", "timeRange": {"from": 1704067200, "to": 1704070800}},
  "baselineGroup": {"filter": "context.service.name:checkout duration:<500", "timeRange": {"from": 1704067200, "to": 1704070800}}
}'

Before and after a deployment — same filter, two windows:

tsuga traces contrast-sets -d '{
  "targetGroup":   {"filter": "context.service.name:checkout", "timeRange": {"from": 1704070800, "to": 1704074400}},
  "baselineGroup": {"filter": "context.service.name:checkout", "timeRange": {"from": 1704063600, "to": 1704067200}}
}'

Each returned value reports targetSupport and baselineSupport (the percentage of each group carrying it), lift (targetSupport / baselineSupport, omitted when the value never appears in the baseline), and pValue. Narrow the findings with topK, minLift, and minSupport; restrict the attributes tested with candidateAttrs.

Metrics

# List all metrics
tsuga metrics list --from=-1h

# Get a specific metric
tsuga metrics get my.metric.name --from=-1h

# List dashboards and monitors that use a metric
tsuga metrics assets-usage my.metric.name

Aggregation

Run aggregation queries with a JSON body:

tsuga aggregation scalar -f query.json
tsuga aggregation timeseries -f query.json

Use --generate-skeleton to get a template:

tsuga aggregation scalar --generate-skeleton > query.json

Service graph

Inspect service dependency graphs:

tsuga service-graph get <SERVICE_ID> --from=-1h --query 'env:prod'

Kubernetes

Explore Kubernetes resources observed across the organization, inferred from your telemetry:

tsuga kubernetes pods --search my-service
tsuga kubernetes clusters
tsuga kubernetes nodes --search ip-10-0
tsuga kubernetes events --search my-pod
tsuga kubernetes pod-details --k8s-cluster prod --k8s-namespace default --pod-name my-pod-abc123

Available resources: pods, clusters, namespaces, nodes, deployments, statefulsets, daemonsets, events (list, with an optional --search), and pod-details, pod-manifest, deployment-details (single-resource lookups, with required identifying flags).

Grok

Test grok parsing rules against sample log lines before using them in a log route:

tsuga grok parse --generate-skeleton > grok-test.json
# edit grok-test.json
tsuga grok parse -f grok-test.json

PromQL

Run a PromQL query against the metrics backend. Returns a timeseries shape matching tsuga aggregation timeseries.

tsuga promql query --generate-skeleton > query.json
# edit query.json
tsuga promql query -f query.json

Or inline:

tsuga promql query -d '{"query":"sum by (\"context.service.name\") (sum_over_time({\"traces.span.metrics.calls\", \"span.kind\"=\"SPAN_KIND_SERVER\"}[5m]))","timeRange":{"from":1704067200,"to":1704070800},"step":"30s"}'

timeRange.from / timeRange.to are Unix timestamps in seconds.

Experimental

Commands under tsuga experimental may change or be removed without notice.

Continuous profiling

# Rank functions by self (flat) and inclusive (cum) sample value, like `go tool pprof -top`
tsuga experimental profiles top --service api --type cpu --from=-1h
tsuga experimental profiles top --service api --type alloc_space --from=-1h --limit 10 -o tsv

# Download the merged profile as raw pprof protobuf and open it with pprof
tsuga experimental profiles pprof --service api --type cpu --from=-1h -O cpu.pb
go tool pprof -http=: cpu.pb

# Raw folded stacks (`root;...;leaf` with a value), with the usual -f / -d / --generate-skeleton
tsuga experimental profiles query -d '{"service":"api","type":"cpu","timeRange":{"from":1704067200,"to":1704070800}}'

--type is a pprof sample type such as cpu, samples, wall, off_cpu, alloc_space, inuse_space, alloc_objects, inuse_objects, or goroutine. --filter takes a Tsuga query over the profile labels; only label equality, negation, and wildcards are accepted.

LLM telemetry

Configure local Claude Code (~/.claude/settings.json) or Codex (~/.codex/config.toml) to ship OpenTelemetry data to your Tsuga cluster. Needs an OTLP base URL and an ingestion API key (not the same as your operation API key).

tsuga setup claude-code --endpoint <OTLP_ENDPOINT> --ingestion-api-key <INGESTION_API_KEY>
tsuga setup codex --endpoint <OTLP_ENDPOINT> --ingestion-api-key <INGESTION_API_KEY>

Both options also read from env (TSUGA_OTLP_ENDPOINT, TSUGA_INGESTION_API_KEY). Pass --no-include-prompts to strip user prompts from telemetry (default: include); for claude-code this also strips tool content, but codex only strips user prompts. The previous config is saved alongside the file as .bak.<ISO>; restart any running claude / codex sessions afterward.

LLM plugins

tsuga install plugin claude-code
tsuga install plugin codex

Adds the tsuga marketplace (tsuga-dev/agent-plugins) and installs the tsuga plugin via the target CLI (claude / codex must be on PATH). For Claude Code, marketplace auto-update is enabled by patching ~/.claude/settings.json with extraKnownMarketplaces.tsuga.autoUpdate = true; pass --no-auto-update to skip. Restart any running claude / codex sessions afterward.

Documentation

Search Tsuga documentation and the full API reference, then fetch a page by path:

tsuga docs search 'log routes'
tsuga docs get explore/query-syntax
tsuga docs get api/aggregateScalar

Feedback

Report friction with Tsuga tools or APIs (a failing command, unusable output, confusing behavior):

tsuga feedback the traces command keeps timing out on large services

Tips

Default output is JSON, so you can pipe to jq:

tsuga dashboards list | jq '.[].name'
tsuga monitors list | jq '.[] | select(.priority == 1)'

Read from stdin with -f -:

echo '{"name": "My Team"}' | tsuga teams create -f -

Implementation

The CLI uses Effect v4 services for HTTP, configuration, filesystem access, subprocesses, and command parsing. Command folders mirror tadmin: each group has a composition index.ts and one file per action, with nearby tests. Cross-directory application imports use @cli/*. packages/common-cli shares OAuth token exchange, browser callbacks, macOS keychain access, output, and closed-pipe handling with tadmin. The CLIs retain separate credential namespaces and authentication policies. Generic field projection lives in common.

Run yarn lint, yarn typecheck, yarn test, and yarn build from packages/cli to verify changes. Lint includes Effect language-service diagnostics.