> ## Documentation Index
> Fetch the complete documentation index at: https://laminarai-docs-lam-1778-self-host-access-control.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# CLI

The `lmnr-cli` is a command-line tool for onboarding a project, querying Laminar data, managing datasets, and annotating debug sessions from your terminal. It is the fastest way to wire up a new project, pull traces into a shell pipeline, script dataset maintenance, or connect an AI coding agent that can shell out, all without leaving the command line.

<Note>
  The CLI is a standalone npm package (`lmnr-cli`) and ships independently from the `@lmnr-ai/lmnr` SDK. You do not need the SDK installed to onboard a project, query data, or manage datasets.
</Note>

## Install

```bash theme={null}
# Run directly with npx (no install)
npx lmnr-cli@latest <command>

# Or install globally
npm install -g lmnr-cli
```

## Quick start

`lmnr-cli setup` takes you from a fresh install to an instrumented project in one command:

```bash theme={null}
lmnr-cli setup
```

It opens your browser to authorize the CLI, then:

1. Logs you in (if you are not already).
2. Lets you pick or create a project.
3. Mints a project API key for your application's SDK and writes `LMNR_PROJECT_API_KEY=...` to your env file (an existing `.env.local` if you have one, otherwise `.env`). If a valid key for this project is already configured, it keeps that one.
4. Links the directory by writing `.lmnr/project.json`.
5. Installs the Laminar agent skill into your project (`.claude/`, `.cursor/`, `.codex/`, or `.agents/`).

The CLI itself never uses that key: it authenticates as you (see [Authenticate](#authenticate)). The key is purely for the SDK in your app to send traces.

Add the SDK to your app, run it, then confirm traces are landing:

```bash theme={null}
lmnr-cli sql query "SELECT * FROM traces ORDER BY start_time DESC LIMIT 1"
```

`setup` is designed to be driven by coding agents. Pass `--json` for a single machine-readable line on stdout:

```bash theme={null}
lmnr-cli setup --json
```

Useful flags:

```bash theme={null}
lmnr-cli setup --project-id <uuid>   # Disambiguate when you can access multiple projects
lmnr-cli setup --no-write-env        # Skip writing ./.env
lmnr-cli setup --no-browser          # Print the device-flow URL instead of opening it
```

Re-running `setup` in the same directory reuses the linked project and keeps a working key in place: if a valid key for this project is already configured (in your environment or env file), it leaves it untouched. If your API key is invalid or revoked it will mint a new one. If your API key does not match the project configured in `.lmnr/project.json` it will abort with an error. Keys stay visible (and revocable) in **Settings → Project API Keys**.

## Authenticate

Every CLI command authenticates as you, the signed-in user. Log in once with `lmnr-cli login` (or run `lmnr-cli setup`, which logs you in as its first step):

```bash theme={null}
lmnr-cli login
```

This starts an OAuth device flow: the CLI prints a verification URL and code and opens your browser. Approve the request to finish signing in. Credentials are stored at `~/.config/lmnr/credentials.json` (fallback precedence `&XDG_CONFIG_HOME/`, `%APPDATA%\`, `~/.config/`). The short-lived access token is refreshed automatically as it nears expiry; if your session is revoked, run `lmnr-cli login` again.

```bash theme={null}
lmnr-cli logout   # Remove the stored credentials
```

## Self-hosting

For a self-hosted deployment, point the CLI at your instance. `login` talks to your frontend (the auth issuer); the data commands (`sql`, `dataset`, `project`, `trace`, `debug`) talk to your API.

The cleanest way is to set the URLs once via environment variables. The CLI reads them from your environment and from a `.env` or `.env.local` file in the current directory.

```bash theme={null}
LMNR_FRONTEND_URL=https://example.com   
LMNR_BASE_URL=https://api.example.com  
LMNR_HTTP_PORT=8000                             
```

With those set, every command works as usual:

```bash theme={null}
lmnr-cli login
lmnr-cli sql query "SELECT 1"
```

You can also pass the URLs per command instead. `login` takes `--frontend-url`; the data commands take `--base-url` (and `--port`):

```bash theme={null}
lmnr-cli login --frontend-url https://laminar.example.com
lmnr-cli sql query "SELECT 1" --base-url https://api.laminar.example.com
```

<Note>
  The CLI does not use a project API key. The `LMNR_PROJECT_API_KEY` that `lmnr-cli setup` writes to your env file is for the Laminar SDK in your application to send traces; the CLI authenticates as you instead.
</Note>

## Directory-scoped projects

Every project command (`sql`, `dataset`, `project`, `trace`, `debug`) resolves which project it targets from the directory you run in. `lmnr-cli setup` writes a `.lmnr/project.json` link file at the project root (it holds the project id and display details, never secrets). Commands then resolve the project in this order:

1. `--project-id <id>` flag.
2. The nearest `.lmnr/project.json`, walking up from the current directory.

So once a directory is linked, every command in it (or any subdirectory) targets that project with no extra flags. Override per command with `--project-id`.

List the projects you can access and see which one is linked here:

```bash theme={null}
lmnr-cli project list
lmnr-cli project list --json
```

The linked project is marked with a `●`.

## Query data with SQL

Run ClickHouse SQL against your project's spans, traces, signal events, and more. `sql` runs against the linked project, so `lmnr-cli login` plus a linked directory (or `--project-id`) is all you need:

```bash theme={null}
lmnr-cli sql query "SELECT name, duration FROM spans WHERE start_time > now() - INTERVAL 1 HOUR LIMIT 20"
```

Add `--json` to emit structured JSON on stdout (messages and errors go to stderr), which makes it trivial to pipe into `jq`, a local script, or an AI coding agent:

```bash theme={null}
lmnr-cli sql query "SELECT trace_id, total_cost FROM spans WHERE span_type = 'LLM' LIMIT 10" --json \
  | jq '.[] | select(.total_cost > 0.01)'
```

List the available tables and columns:

```bash theme={null}
lmnr-cli sql schema
```

For the full schema and query guide, see [SQL Editor](/platform/sql-editor).

<Note>
  Only `SELECT` queries are allowed. The query runs scoped to your project automatically; no tenant filter is needed in your WHERE clause.
</Note>

## Manage datasets

List, push, pull, and create datasets from files on disk. Supported formats: `.jsonl`, `.json`, `.csv`. Like `sql`, these commands run against the linked project.

```bash theme={null}
# List all datasets in the project
lmnr-cli dataset list --json

# Push new datapoints into an existing dataset
lmnr-cli dataset push data.jsonl -n my-dataset

# Pull a dataset down to a local file
lmnr-cli dataset pull output.jsonl -n my-dataset

# Create a new dataset from a file, writing a local copy with dataset IDs
lmnr-cli dataset create my-dataset data.jsonl -o my-dataset.jsonl
```

See [Datasets CLI](/datasets/cli) for the full dataset workflow including versioning semantics.

## Annotate debug sessions

These commands are the operational layer for the [Debugger](/debugger/process): you run the agent with `LMNR_DEBUG=true`, then use these to name the session, write per-trace notes, and open the session view. Like the other commands, they run against the linked project.

<Note>
  None of these commands need an id passed in. By default they target the session in `.lmnr/debug-session.json` (the most recent `LMNR_DEBUG=true` run in this directory), and `trace append-note` targets that session's latest trace. Pass `--session-id` or `--trace-id` to target a different one.
</Note>

### trace append-note

Append a markdown note to a trace (stored in `rollout.note` trace metadata). Notes are append-only: each call adds a paragraph to the existing note. The note text is the only required argument; the note lands on the latest trace of the current debug session unless you pass `--trace-id`.

```bash theme={null}
lmnr-cli trace append-note "## What this run showed
Length cap is working. Next: check citations."

lmnr-cli trace append-note "Length cap is working." --trace-id <trace-id>
```

Span references in the note are written as XML tags; the Laminar UI renders them as clickable chips:

```bash theme={null}
lmnr-cli trace append-note "<span id='<spanId>' name='synthesis call' />"
```

### debug session new

Mint a fresh debug session and reset `.lmnr/debug-session.json` to it. The next `LMNR_DEBUG=true` run in this directory rejoins the new session instead of continuing the previous one. Use this to start a clean investigation.

```bash theme={null}
lmnr-cli debug session new
lmnr-cli debug session new --json
lmnr-cli debug session new --no-browser
```

The bare session id prints to stdout (so an agent can capture it); `--json` emits `{"sessionId","projectId","debuggerUrl"}` instead. The command opens the session in your browser unless you pass `--no-browser`.

### debug session open

Open the debug session's debugger page in your browser. With no flag it opens the session in `.lmnr/debug-session.json`; pass `--session-id` to open another. The URL also prints to stdout (`--json` emits `{"sessionId","debuggerUrl"}`). This command is local-only: no login or network call.

```bash theme={null}
lmnr-cli debug session open
lmnr-cli debug session open --session-id <session-id>
```

### debug session set-name

Set the display name of the current debug session (the one in `.lmnr/debug-session.json`), or pass `--session-id` to name another. The session must already exist (created by a `LMNR_DEBUG=true` run or `debug session new`). You can also rename a session inline by clicking its title in the session view.

```bash theme={null}
lmnr-cli debug session set-name "Fix report length + search tool"
lmnr-cli debug session set-name "Fix report length" --session-id <session-id>
```

### debug session summary

Print every trace in the debug session with its note, oldest first. Use this to re-orient in an ongoing session after a context reset. Defaults to the current session; pass `--session-id` for another.

```bash theme={null}
lmnr-cli debug session summary
lmnr-cli debug session summary --session-id <session-id> --json
```

Output is one block per trace: the markdown note followed by a `<trace id="..." end-time="..."/>` tag you can feed into SQL queries.

See [Debugger](/debugger/process) for the full record/replay process.

## Piping and agent-friendly output

The CLI is designed to be scriptable and to plug cleanly into AI coding agents:

* **One-shot onboarding.** `lmnr-cli setup --json` emits a single machine-readable line (project id, minted key, dashboard URL) and uses distinct exit codes so an agent can branch on the failure mode: `6` login failed, `7` no project to select, `8` `.env` write failed, `9` key minting failed, `10` project discovery failed.
* **Structured output on stdout, logs on stderr.** Every command that supports it takes `--json` and prints machine-readable output to stdout, while human-friendly progress messages are written to stderr. This keeps pipes clean.

Combined with `sql query --json`, this makes the CLI a drop-in SQL layer for any agent that can run shell commands, with no SDK install required.

## Help

Every command accepts `-h` / `--help`:

```bash theme={null}
lmnr-cli --help
lmnr-cli setup --help
lmnr-cli login --help
lmnr-cli project --help
lmnr-cli sql --help
lmnr-cli sql query --help
lmnr-cli dataset --help
lmnr-cli trace --help
lmnr-cli debug --help
lmnr-cli debug session --help
lmnr-cli debug session new --help
lmnr-cli debug session open --help
```

## What's next

<CardGroup cols={2}>
  <Card title="SQL Editor" href="/platform/sql-editor">
    The UI counterpart for ad-hoc SQL queries, with schema reference and examples.
  </Card>

  <Card title="MCP Server" href="/platform/mcp">
    Connect Claude Code, Cursor, or any MCP client to Laminar directly.
  </Card>

  <Card title="Datasets CLI workflow" href="/datasets/cli">
    End-to-end example of pulling, editing, and pushing a dataset.
  </Card>

  <Card title="Debugger" href="/debugger/introduction">
    Rerun long-running agents from a checkpoint without leaving the page.
  </Card>
</CardGroup>
