# CLI

`tglow` is the Tailglow command line. Every endpoint in the [API reference](/api) is a command, because both are generated from the same source: the API's own routes and validations. A new endpoint becomes a new command with no separate release, and the CLI cannot describe an API that does not exist.

It is built for two readers at once. In a terminal it prints tables and asks before deleting. Piped, redirected, or run by an agent, it emits JSON and never prompts.

## Installation

```bash
npm install -g @tailglow/cli
```

Node 18.3 or newer. `bun add -g @tailglow/cli` and `pnpm add -g @tailglow/cli` work the same way.

Verify it:

```bash
tglow --version
```

Prefer a shorter name? Alias it rather than installing over one, since `tg` belongs to other tools on many systems:

```bash
alias tg=tglow
```

## Authenticating

Sign in from the terminal:

```bash
tglow login
```

It asks how you want to sign in, opens the approval page in your browser, and waits. Check that the page shows the code your terminal printed, then approve.

- **Sign in with your Tailglow account** gives the CLI a session that acts as you, with what your role allows in each of your teams. It starts in the team you choose; `--team` or `tglow config set team` switches it. It is listed as **CLI** under **Profile > Security**, ends when you sign out of every device, and ends on its own after six months unused.
- **Sign in with an API key** creates a key for one team, named after this machine, with the permissions you choose. The team needs a project first.

`--method account` or `--method api-key` skips the question.

Without a terminal, for example when an agent runs it, `tglow login` prints the link and the code and exits. Approve the sign-in, then run `tglow login --wait` to finish. It exits `0` once signed in, `75` while approval is still pending (run it again), and `1` if the sign-in was denied, expired or withdrawn, or the API could not be reached (the sign-in is kept, so run it again once the connection is back).

```bash
tglow whoami    # who the CLI acts as, in which team, with which credential
tglow logout    # end the session, or delete the key, that tglow login created
```

The credential is stored in `~/.tailglow/config.json`, readable only by you, and is only ever sent to the API that issued it.

### API keys

An API key you already have works too. Create one in the dashboard under **Team settings**, then store it once:

```bash
tglow config set api_key tg_api_...
```

A stored key is never printed back. Credentials are tried in this order:

| Source                     | Use it for                                   |
| -------------------------- | -------------------------------------------- |
| `--api-key <key>`          | A single call. Visible in your shell history |
| `TAILGLOW_API_KEY`         | CI, containers, and anything scripted        |
| `tglow login`              | Your own machine                             |
| `tglow config set api_key` | A key you created in the dashboard           |

In CI, prefer the environment variable. A key passed as a flag appears in the process list.

## Getting around

The shape is always the same:

```bash
tglow <resource> <command> [flags]
```

Three levels of help, and between them they are the whole manual:

```bash
tglow                              # every resource, and the flags that apply everywhere
tglow drains                       # every command on drains
tglow drains create --help         # every flag, its type, and its accepted values
```

Command help is generated from the same validations the API enforces, so a required field is required here for the same reason it is required there.

## Reading the docs

Every guide and API reference page ships inside the CLI as markdown:

```bash
tglow docs                  # the index of every page
tglow docs guides/sdk       # one page
tglow docs /api/drains.md   # any link from the index works as it is
```

The pages match the version of the CLI you have installed, so they describe the commands it can run, and they work without a network connection. Each page ends with a link to its latest version online.

Unlike other commands, `tglow docs` prints markdown even when its output is piped, because the reader is usually an agent. Add `--json` to get `{ path, url, content }` for a page, or `{ index, pages, online }` for the index.

## Working with a project

Most commands act on a project. Set it once instead of repeating it:

```bash
tglow config set project prj_...
tglow metrics list
```

`--project` overrides the stored default for a single call. Every other id has to be named explicitly: only `project` and `team` fall back to configuration, so nothing in your environment can quietly become the target of a delete.

## Flags

Field names are snake_case in the API and kebab-case on the command line: `time_window_minutes` becomes `--time-window-minutes`. Path parameters are flags too, never positional.

```bash
tglow sources create --project prj_x --name "Web events"        # a string
tglow pages create --project prj_x --name Status --is-public    # true
tglow pages create --project prj_x --name Status --is-public=false
tglow metrics create --project prj_x --group-by user_id,country # a list
tglow views create-join --project prj_x --joins '[{"view_id":"view_b","on":"user_id"}]'
```

A boolean is passed alone for true, or written attached for false. Anything typed `object`, `object[]`, or `Scopes` takes JSON as a single argument.

## Output

A terminal gets a table. Everything else gets JSON, so `| jq` needs no flag:

```bash
tglow projects list | jq -r '.data[].name'
```

JSON is the API's response as it was sent, envelope included: read `.data` for results and `.pagination.next_cursor` to continue. `--json` forces it when you want JSON in a terminal.

Failures go to stderr and follow the same mode, so a pipeline reading stdout never has to tell a result apart from an explanation of why there is none.

## Long lists

List commands paginate. `--all` follows the cursor until the results run out or `--max` is reached:

```bash
tglow metrics list --project prj_x --all --max 500
```

The cap defaults to 10,000 and exists because records and collection documents are unbounded. A run that stops early prints the exact command to continue with. Under `--json`, `--all` returns `{ data, truncated, next_cursor }` instead, so a caller can resume on its own with `--after`.

`--all` owns paging, so it does not combine with `--limit` or `--before`. Use `--limit` on its own to size a single page.

## Deleting

In a terminal, a delete asks first. `--yes` skips the question.

**Without a terminal, a delete runs immediately and is never confirmed.** That is deliberate, so scripts and agents are not blocked on a question they cannot answer, but it means a delete in CI happens the moment it is called.

Most resources delete softly: the response tells you when permanent removal happens.

## Scripting it

The CLI is designed to be driven by other programs, including AI agents:

```bash
export TAILGLOW_API_KEY=tg_api_...
tglow metrics create --help --json     # the full contract for one command, as data
```

`--help --json` returns the command's flags, types, requiredness, accepted values, and the syntax for each one. An agent can read that and construct a valid call without any other documentation.
