Skip to main content

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)
--online-window MINUTES Minutes since last seen to still count a device as online (default: 5; env: QUERY_TS_ONLINE_WINDOW)
--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.

A device counts as online if it holds a live connection to the Tailscale control server, or if it was last seen within the --online-window (default 5 minutes). The Tailscale API has no plain online flag, and idle-but-reachable devices (phones in particular) drop the control connection, so widen the window if such devices read as offline, e.g. --online-window 15.

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

Metadata

Release files for query-ts 1.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for query-ts 1.1.2
File Size Uploaded
query_ts-1.1.2.tar.gz 57.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for query-ts 1.1.2
File Interpreter ABI Platform
query_ts-1.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 77.9 kB

Release files / query_ts-1.1.2.tar.gz

Download URL query_ts-1.1.2.tar.gz
Size 57.2 kB
Tags Source
SHA-256 checksum
How to use checksums
a3ab96a68c7b991730d0d886ebe959df52b631096d84dc5ac422975000019937
BLAKE2b-256 checksum
How to use checksums
e5b41c1bc224de639fc743c3a1c695db7a1421957d1b0dc0f85e8a8b5b4a7187
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 19, 2026.

Transparency log

Release files / query_ts-1.1.2-py3-none-any.whl

Download URL query_ts-1.1.2-py3-none-any.whl
Size 20.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ac3431bf78c8e3f8941088d9eabc61708d400766e77e882c8b9a267641b816f5
BLAKE2b-256 checksum
How to use checksums
520ab25748af160b0280f57e5ee0a3cd4d14e3890303351fbd1e7ba81df62b04
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 19, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.1.2 This release

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page