Skip to main content
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.
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.

Install

# 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:
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). 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:
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:
lmnr-cli setup --json
Useful flags:
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):
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.
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, 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.
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:
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):
lmnr-cli login --frontend-url https://laminar.example.com
lmnr-cli sql query "SELECT 1" --base-url https://api.laminar.example.com
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.

Directory-scoped projects

Every project command (sql, dataset, project, 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:
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:
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:
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:
lmnr-cli sql schema
For the full schema and query guide, see SQL Editor.
Only SELECT queries are allowed. The query runs scoped to your project automatically; no tenant filter is needed in your WHERE clause.

Ask the agent

When you do not want to write the SQL yourself, ask Laminar Agent a question in plain language. It runs read-only SQL and reads trace context for you, then answers grounded in your project’s data:
lmnr-cli ask "What failed in the most recent run for my dev-claude session?"
Like the other commands, ask runs against the linked project and authenticates as the signed-in user, so lmnr-cli login plus a linked directory (or --project-id) is all you need.
lmnr-cli ask "List the 5 slowest traces in the last hour and explain the slowest one"
lmnr-cli ask "How much did we spend on LLM calls today, broken down by model?" --project-id <uuid>

Continue a conversation

Each answer prints a conversation id after it. Pass that id to --conversation on your next question to continue the same conversation, so the agent keeps the earlier context and you can ask follow-ups:
lmnr-cli ask "What failed in the most recent run for my dev-claude session?"
# ...answer, then: continue with: lmnr-cli ask "<question>" --conversation <id>
lmnr-cli ask "and which model did it use?" --conversation <id>
With --json, the conversation id comes back as conversationId in the output ({ answer, conversationId, tools }), so a script can capture it and thread it through a multi-turn exchange:
lmnr-cli ask "summarize the most expensive trace today" --json
See Laminar Agent for the full list of what it can do and the other surfaces (MCP, Slack) it runs on.

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.
# 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 for the full dataset workflow including versioning semantics.

Annotate debug sessions

These commands are the operational layer for the Debugger: you run the agent with LMNR_DEBUG=true, then use these to name the session, write notes, and open the session view. Like the other commands, they run against the linked project.
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). Pass --session-id to target a different one.

debug session add-note

Attach a markdown note to the debug session. Each call adds a standalone note, slotted into the session timeline by time between the session’s runs and evaluations, both in the session view and in debug session summary. The note text is the only required argument.
lmnr-cli debug session add-note "## What this run showed
Length cap is working. Next: check citations."

lmnr-cli debug session add-note "Length cap is working." --session-id <session-id>
Span references in the note are written as XML tags; the Laminar UI renders them as clickable chips:
lmnr-cli debug session add-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.
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.
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.
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 the debug session’s full timeline, oldest first: every run, evaluation, and note. Use this to re-orient in an ongoing session after a context reset. Defaults to the current session; pass --session-id for another.
lmnr-cli debug session summary
lmnr-cli debug session summary --session-id <session-id> --json
Traces and evaluations print as self-closing <trace id="..."/> and <evaluation id="..."/> tags you can feed into SQL queries; notes print as their raw markdown. With --json, the output is an array of {"id","createdAt","type","content"} blocks. See Debugger 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:
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 debug --help
lmnr-cli debug session --help
lmnr-cli debug session new --help
lmnr-cli debug session open --help

What’s next

SQL Editor

The UI counterpart for ad-hoc SQL queries, with schema reference and examples.

MCP Server

Connect Claude Code, Cursor, or any MCP client to Laminar directly.

Datasets CLI workflow

End-to-end example of pulling, editing, and pushing a dataset.

Debugger

Rerun your agent from a checkpoint and prove the fix with an eval.