> ## Documentation Index
> Fetch the complete documentation index at: https://docs.traffical.io/llms.txt
> Use this file to discover all available pages before exploring further.

# CLI

> Log in, link a project, and sync parameters, events, and metrics between your repo and Traffical — config-as-code from the command line.

`@traffical/cli` manages your Traffical configuration as code. You define parameters, events, and metrics in a [`.traffical/` directory](/tools/config-file), version-control them alongside your application, and sync with the platform with `push`, `pull`, and `status`.

## Why config-as-code

* **Single source of truth** — parameter and event definitions live in your repo, reviewed in pull requests like any other code.
* **No drift** — definitions you push become **synced**: read-only in the dashboard, so the repo and the platform can't disagree.
* **Typed events** — generate TypeScript types from your event schemas so invalid `track()` calls fail at compile time.
* **CI-enforceable** — `traffical status` exits non-zero on drift, so you can gate merges on the repo and platform being in sync.

Policies, allocations, and experiment lifecycle decisions still live in the [dashboard](/dashboard/overview) — the CLI owns the *definitions*, not the rollout state.

## Installation

```bash theme={null}
npm install -g @traffical/cli
# or run without installing
bunx @traffical/cli init
```

Requires Node.js 18+.

## Quickstart

<Steps>
  <Step title="Initialize">
    From your project root, scaffold the `.traffical/` directory and link a project:

    ```bash theme={null}
    traffical init
    ```

    `init` logs you in, lets you pick an org and project, writes [`config.yaml`](/tools/config-file#configyaml) and [`project.yaml`](/tools/config-file#projectyaml), creates a public SDK key, and drops example code for your framework.
  </Step>

  <Step title="Edit your config">
    Add or change parameters and events in `.traffical/config.yaml`. See the [configuration file reference](/tools/config-file) for every field.
  </Step>

  <Step title="Push to Traffical">
    ```bash theme={null}
    traffical push
    ```
  </Step>

  <Step title="Check for drift">
    ```bash theme={null}
    traffical status
    ```
  </Step>
</Steps>

## Authentication

For interactive use, log in once with the browser-based device flow:

```bash theme={null}
traffical login
```

This opens your browser, asks you to confirm a code, and stores a session at `~/.config/traffical/auth.json` (mode `0600`). The session holds a refresh token and renews access tokens automatically, so you rarely log in again.

```bash theme={null}
traffical whoami            # show the active identity and linked project
traffical whoami --verify   # live-check the session against the server
traffical logout            # remove the local session
```

<Note>
  `whoami` without `--verify` reports the *cached* session. A cached session can still be reported as authenticated after it has ended server-side — use `--verify` when you need a definitive answer.
</Note>

### Credential precedence

The CLI resolves a bearer token in this order:

1. `--api-key <key>` on the command line
2. `TRAFFICAL_API_KEY` environment variable (org-scoped key — the **CI path**)
3. `TRAFFICAL_API_TOKEN` environment variable (pre-minted JWT, for agents)
4. The device-flow session from `traffical login`
5. A legacy `~/.trafficalrc` profile (`--profile <name>`) — deprecated

For CI, set `TRAFFICAL_API_KEY` and skip `login` entirely.

```bash theme={null}
# Headless / agent login with a pre-minted token
traffical login --token "$JWT"
# Print the URL + code instead of opening a browser
traffical login --no-browser
```

## Selecting a project

A repo is linked to exactly one Traffical project, recorded in [`.traffical/project.yaml`](/tools/config-file#projectyaml).

```bash theme={null}
traffical link                      # interactive org + project picker
traffical link --org acme --project mahally
traffical unlink                    # remove the link (leaves config.yaml)
```

When a flag is omitted, the CLI prompts: a select list for ≤10 options, a search box beyond that. Pass `--force` to re-link a repo that's already linked.

Manage orgs and projects directly:

```bash theme={null}
traffical org list                  # orgs you belong to
traffical org use <key>             # default org for commands that need one

traffical project list              # projects in the active org
traffical project create <name> --link
traffical project use <key>         # alias of `link --project <key>`
```

## Syncing configuration

<Steps>
  <Step title="status — see the difference">
    ```bash theme={null}
    traffical status
    ```

    Shows what's synced, what has local changes to push, and what exists only in the dashboard. Exits with code `10` when there's drift, so it doubles as a CI check.

    ```
    Connected to: Salla PoC/Mahally (proj_ST6qGDbR)

    Parameters
      Synced: 7 parameters
      Dashboard-only: 2 parameters
        ui.sees-feature-y (created 5/20/2026)

    Events
      Synced: 4 events

    Metrics
      Dashboard-only: 4 metrics
    ```
  </Step>

  <Step title="push — repo → Traffical">
    ```bash theme={null}
    traffical push [--dry-run] [--prune]
    ```

    Creates new definitions and updates existing synced ones. Pushed definitions become read-only in the dashboard.

    * `--dry-run` — validate and print the diff without applying.
    * `--prune` — archive synced definitions that have been removed from the file. Without it, removals stay on the platform.
  </Step>

  <Step title="pull — Traffical → repo">
    ```bash theme={null}
    traffical pull [--include-types]
    ```

    Downloads synced parameters, events, and property groups into `config.yaml`. Dashboard-only definitions stay in the dashboard until you `import` them. `--include-types` runs `generate-types` afterwards.
  </Step>

  <Step title="sync — both directions">
    ```bash theme={null}
    traffical sync [--all] [--dry-run] [--prune]
    ```

    Pushes local changes and pulls new remote definitions in one pass. On conflict, **local wins**. `--all` syncs every config file in the repo.
  </Step>
</Steps>

### Importing dashboard definitions

Definitions created in the dashboard are *dashboard-only* until you adopt them into code:

```bash theme={null}
traffical import param ui.accent_color   # one parameter
traffical import param 'ui.*'            # wildcard
traffical import metrics --all           # all metrics → metrics.yaml
traffical import metrics add_to_cart_rate
```

## Type-safe events

Generate TypeScript types from your event definitions so invalid event names and properties become compile errors:

```bash theme={null}
traffical generate-types          # writes .traffical/traffical.generated.ts
traffical generate-types -o src/traffical.generated.ts
```

This emits a `TrafficalEventProperties` map — event name → typed property shape. Wrap your client's `track`:

```typescript theme={null}
import type { TrafficalEventProperties } from "./traffical.generated";

type TypedTrack = <E extends keyof TrafficalEventProperties>(
  event: E,
  options: { unitKey: string; properties?: TrafficalEventProperties[E]; decisionId?: string }
) => void;

export const track = traffical.track.bind(traffical) as TypedTrack;
```

```typescript theme={null}
track("add_to_cart", { unitKey: "user_789", properties: { product_id: "p_1" } }); // ✅
track("add_to_cart", { unitKey: "user_789", properties: { unknown: true } });      // ❌ compile error
```

Run it after every `pull` (or in CI) to keep types in sync. See [Type-safe events](/guides/type-safe-events) for the full flow.

## CI/CD integration

<CodeGroup>
  ```yaml Validate on PRs theme={null}
  # .github/workflows/traffical.yml
  name: Traffical
  on: [pull_request]
  jobs:
    validate:
      runs-on: ubuntu-latest
      steps:
        - uses: actions/checkout@v4
        - uses: oven-sh/setup-bun@v1
        - run: bunx @traffical/cli status   # exits 10 on drift
          env:
            TRAFFICAL_API_KEY: ${{ secrets.TRAFFICAL_API_KEY }}
  ```

  ```yaml Sync on merge theme={null}
  # .github/workflows/traffical-sync.yml
  name: Traffical sync
  on:
    push:
      branches: [main]
      paths: [".traffical/**"]
  jobs:
    sync:
      runs-on: ubuntu-latest
      steps:
        - uses: actions/checkout@v4
        - uses: oven-sh/setup-bun@v1
        - run: bunx @traffical/cli push --prune
          env:
            TRAFFICAL_API_KEY: ${{ secrets.TRAFFICAL_API_KEY }}
  ```
</CodeGroup>

## Command reference

| Command                           | Description                                         |
| --------------------------------- | --------------------------------------------------- |
| `login`                           | Authenticate via browser (OAuth device flow).       |
| `logout`                          | Remove the local session.                           |
| `whoami`                          | Show the active identity and linked project.        |
| `init`                            | Log in, link a project, and scaffold `.traffical/`. |
| `link` / `unlink`                 | Link the repo to a project / remove the link.       |
| `org list` / `org use`            | List orgs / set the default org.                    |
| `project list` / `create` / `use` | Manage projects in the active org.                  |
| `status`                          | Show drift between local and remote.                |
| `push`                            | Send local definitions to Traffical.                |
| `pull`                            | Pull synced definitions into the repo.              |
| `sync`                            | Bidirectional sync (local wins on conflict).        |
| `import param` / `import metrics` | Adopt dashboard definitions into code.              |
| `generate-types`                  | Generate TypeScript types from event definitions.   |

## Global options

| Option                 | Description                                                 |
| ---------------------- | ----------------------------------------------------------- |
| `-c, --config <path>`  | Path to the config file (default `.traffical/config.yaml`). |
| `-b, --api-base <url>` | Override the API endpoint.                                  |
| `-j, --format <fmt>`   | `human` (default) or `json`.                                |
| `-q, --quiet`          | Suppress non-essential output.                              |
| `-p, --profile <name>` | Legacy `~/.trafficalrc` profile (deprecated).               |

Environment variables: `TRAFFICAL_API_KEY`, `TRAFFICAL_API_TOKEN`, `TRAFFICAL_API_BASE`.

## Exit codes

| Code | Meaning                                               |
| ---- | ----------------------------------------------------- |
| `0`  | Success.                                              |
| `1`  | Validation error in config.                           |
| `2`  | Authentication error (not logged in / token invalid). |
| `3`  | Network or API error.                                 |
| `4`  | Not linked (no `project.yaml`).                       |
| `10` | Drift detected (`status`).                            |
| `11` | Experiment needs attention.                           |

## Next steps

<CardGroup cols={2}>
  <Card title="Configuration file" icon="file-code" href="/tools/config-file">
    Every field in config.yaml, project.yaml, and metrics.yaml.
  </Card>

  <Card title="Parameters" icon="sliders" href="/concepts/parameters">
    Typed values with defaults.
  </Card>

  <Card title="Type-safe events" icon="code" href="/guides/type-safe-events">
    Codegen, SDK typing, and dev-mode validation.
  </Card>

  <Card title="Quickstart" icon="rocket" href="/quickstart">
    Resolve a parameter and track an event.
  </Card>
</CardGroup>
