Skip to main content

CLI for querying the Tailscale API

Project description

query-ts

A command-line tool for querying the Tailscale API. List and filter devices, users, groups, services, and ACLs using a small, glob-friendly query language, and render the results as a table, JSON, YAML, or plain text.

Features

  • Query devices (default), users, groups, services, and ACLs.
  • A simple filter DSL with glob matching, tag matching, AND/OR, parentheses, and negation.
  • Human-friendly coloured tables by default, plus --json, --yaml, and --plain output for scripting.
  • Authenticates with either a Tailscale API key or OAuth2 client credentials (tokens fetched and cached automatically).

Installation

Install with Homebrew:

brew install 1stvamp/tap/query-ts

Or with snap:

sudo snap install query-ts

Or from PyPI with your tool of choice:

pip install query-ts
# or, to install as an isolated tool:
uv tool install query-ts
# or:
pipx install query-ts

This installs a query-ts command and requires Python 3.11+.

To run from a checkout instead (the project is managed with uv):

uv run query-ts --help

Authentication

Provide either an API key or OAuth2 client credentials, not both. One of the two is required; the CLI exits with an error if no credentials are given.

API key

export TAILSCALE_API_KEY="tskey-api-..."
# or pass it inline with -k/--api-key

OAuth2 client credentials

Both the ID and secret are required together:

export TAILSCALE_OAUTH_CLIENT_ID="..."
export TAILSCALE_OAUTH_CLIENT_SECRET="..."
# or pass --oauth-client-id and --oauth-client-secret

An access token is obtained via the client_credentials grant and cached for its lifetime, refreshing automatically before it expires.

Tailnet

By default the authenticated user's own tailnet (-) is used. Override it with -n/--tailnet or the TAILSCALE_TAILNET environment variable.

Usage

query-ts [QUERY] [OPTIONS]

QUERY is an optional filter expression. Without it, all resources of the selected type are listed.

# All devices, as a table
query-ts

# Devices whose name starts with "web-"
query-ts 'web-*'

# Production-tagged devices that aren't deprecated
query-ts 'env:production -tag:deprecated'

# Users matching a pattern
query-ts --users 'admin*'

# JSON output for two name patterns
query-ts --json 'web-* OR api-*'

# Comma-separated device names (implies plain output)
query-ts --comma 'env:prod'

# List ACL groups
query-ts --type=groups

Query language

Patterns are glob-style (fnmatch) and matched case-insensitively against resource names.

Name patterns

Pattern Matches
web-* names starting with web-
*.example.com FQDNs ending in .example.com

Tag patterns

A word containing a colon is treated as a tag filter. The prefix:suffix form expands to the tag prefix-suffix:

Pattern Matches tag
tag:env-prod env-prod
env:prod env-prod (same as above)
env:prod* env-prod, env-production, etc. (glob on the suffix)

Logical operators

Expression Meaning
web AND env:prod both conditions (AND is the default)
web env:prod implicit AND (same as above)
web OR env:prod either condition
(web OR api) env:prod parentheses for precedence

AND and OR are case-insensitive.

Negation

A leading - negates a term:

query-ts '-web-*'            # exclude names matching web-*
query-ts '-tag:env-prod'     # exclude tagged resources

A query that begins with - (such as a negation) would otherwise be mistaken for a command-line option. Use -- to stop option parsing and pass it as the query:

query-ts -- -web-*          # exclude names matching web-*

Options

Resource type

Flag Description
--devices Query devices (default)
--users Query users
--groups Query ACL groups
--services Query Tailscale Services
--acl Query ACL rules
-t, --type TYPE Resource type: devices, users, groups, services, acl

Output format

Flag Description
-j, --json Output as JSON
-y, --yaml Output as YAML
-p, --plain Output as plain text (newline-separated names)
-f, --format FORMAT Output format: table, json, yaml, plain

The default format is a coloured table.

Plain-text output

Flag Description
-s, --separator SEP Field separator for plain output (default: newline)
-c, --comma Use a comma separator; selects plain output unless a format is set explicitly
--field FIELD Field to extract in plain output (e.g. name, id)

These options only affect plain output. When --field is omitted, a default is chosen per resource type (hostname for devices, login for users).

Connection & authentication

Flag Description
-k, --api-key KEY Tailscale API key (env: TAILSCALE_API_KEY)
--oauth-client-id ID OAuth2 client ID (env: TAILSCALE_OAUTH_CLIENT_ID)
--oauth-client-secret SECRET OAuth2 client secret (env: TAILSCALE_OAUTH_CLIENT_SECRET)
-n, --tailnet NET Tailnet name, or - for the authenticated user's tailnet (env: TAILSCALE_TAILNET)

Display

Flag Description
--color / --no-color Force or disable colour output (auto-detected by default)
--show COLS Comma-separated table columns to always show in full (e.g. --show last-seen,tags)
--version Show the version and exit
-h, --help Show help and exit

Responsive tables

The default table output adapts to your terminal width. When space is tight it degrades gracefully: list columns (IP addresses, tags, members) wrap onto multiple lines first, then the lowest-priority columns are dropped, then long values are shortened (emails lose their domain, timestamps drop the time). Hostname and Tags are never dropped.

For devices, Last Seen is hidden by default and the online state is shown as a coloured dot in the Online column. Use --show last-seen to add the timestamp column, or name any columns you always want kept in full, e.g. --show ip,tags,last-seen. Columns passed to --show are exempt from the automatic dropping and shortening.

Development

# Install dependencies (including dev tools)
uv sync

# Run the test suite
uv run pytest tests/ -v

Tests use respx to mock the Tailscale HTTP API, so no real credentials or network access are required.

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

query_ts-1.1.1.tar.gz (56.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

query_ts-1.1.1-py3-none-any.whl (19.9 kB view details)

Uploaded Python 3

File details

Details for the file query_ts-1.1.1.tar.gz.

File metadata

  • Download URL: query_ts-1.1.1.tar.gz
  • Upload date:
  • Size: 56.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for query_ts-1.1.1.tar.gz
Algorithm Hash digest
SHA256 d76ebd299151d1fe60d11f6f079f469e958a8f8639bdf72f60b6546f23c13edf
MD5 8cb278e22cac3292318d8aad563c83a2
BLAKE2b-256 9fe97f8768bf55857b88452f92e3af36b381d107d525a73e8de912fbf32f05f9

See more details on using hashes here.

Provenance

The following attestation bundles were made for query_ts-1.1.1.tar.gz:

Publisher: release.yml on 1stvamp/query-ts

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file query_ts-1.1.1-py3-none-any.whl.

File metadata

  • Download URL: query_ts-1.1.1-py3-none-any.whl
  • Upload date:
  • Size: 19.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for query_ts-1.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 20e15dd2452bcdc3bdcf00226e06daf736c0b198b98bfa6de94d28f09e8caab9
MD5 cc0b880dfaeb66ef6e62bb60513c0f2c
BLAKE2b-256 1041d66f8ddd4c6f63707c47df53b1756f0e726620e15692a568c0329f138aed

See more details on using hashes here.

Provenance

The following attestation bundles were made for query_ts-1.1.1-py3-none-any.whl:

Publisher: release.yml on 1stvamp/query-ts

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page