Skip to main content

Lynk CLI

lynk is the command-line interface for the Lynk semantic layer platform. Log in once with your browser, then build your semantic layer and query it over SQL — all from your terminal.

Install

The CLI is a standalone Python package. Install it as an isolated tool:

# with uv
uv tool install lynk-cli

# or with pipx
pipx install lynk-cli

Quickstart

lynk auth login            # opens your browser to authenticate
lynk auth whoami           # confirm who you are and your active tenant
lynk build run             # build / validate your semantic layer
lynk setup --harness claude   # install the Lynk plugins into this project (Claude Code)

Commands

-h works anywhere --help does, on the root app and on every group and command.

-f json always writes exactly one valid JSON document to stdout and nothing else, so it pipes into jq unconditionally. Everything the human report shows as context is a field in that document — build local carries its archive summary, and a branch with no builds is null rather than empty output. Progress and warnings go to stderr.

lynk auth login

Authenticates via your browser using OAuth (Authorization Code + PKCE) and stores your tokens securely in the OS keyring. The active tenant is chosen during the browser login flow, so login is single-tenant.

lynk auth logout

Removes your stored credentials and revokes the session.

lynk auth whoami

Shows the authenticated user, active tenant, and token expiry. -f json prints the same fields as a JSON document for scripting.

lynk build

A command group for building and inspecting the semantic layer.

lynk build run builds (validates) the semantic layer for a branch and prints a report — a summary on success, a grouped issue list on failure. Exits non-zero when the build is invalid (CI-friendly). A commit that was already built reuses its build.

lynk build run                 # build the current git branch
lynk build run -b main         # build a specific branch
lynk build latest              # show the report for the latest build (any status)
lynk build status              # show just the latest build's status / commit / time
lynk build run -f json         # raw JSON instead of the report (any build command)

For run / latest / status the branch defaults to your current git branch. build latest / build status report the latest remote build — builds created by build local are excluded from those lookups by the API.

lynk build local zips your .lynk/ directory at HEAD and uploads it, so it needs no git integration on the server side. It always builds the branch you have checked out, and refuses to run while .lynk/ has uncommitted changes — the build is recorded against a commit sha, so the upload has to be what that sha names. Changes under .lynk/evals/ are the exception: a build never reads your test cases, so editing them doesn't block one. Changes elsewhere in the repo don't matter either. --dry-run prints the archive summary without uploading.

lynk build local               # zip and upload .lynk/ at HEAD
lynk build local --dry-run     # build the archive but don't send it
lynk build local -f json       # raw JSON instead of the report

lynk evals

A command group for running the agent pipeline (explore -> text-to-sql) against a dataset of test cases and grading the results, so you can catch regressions before they reach customers. Requires an existing build for the checked-out commit — run lynk build local or lynk build run first.

Test cases are authored as a flat YAML list under .lynk/evals/: .lynk/evals/dataset.yml is the recommended single file, but every *.yml/*.yaml in that directory is read and merged. Each case needs at minimum a name and a domain; everything else (the fields that describe the question, the expected entities, labels, etc.) is forwarded to the API as authored — run lynk evals case-schema to see the full field list the backend expects.

# .lynk/evals/dataset.yml
- name: total-revenue-last-quarter
  domain: sales
  labels: [smoke]
  entities: [order]
  request: "What was our total revenue last quarter?"

Only name and domain are interpreted by the CLI; the remaining field names are the backend's, so take them from lynk evals case-schema rather than from this example.

lynk evals case-schema           # print the case field schema (authoring reference)
lynk evals validate               # check every case: locally, then against the API
lynk evals run                    # run every case through the pipeline
lynk evals run --dry-run          # show which cases would run, without sending anything
lynk evals run -F smoke           # only cases labeled "smoke"
lynk evals run -F smoke -F entity:team  # only cases labeled BOTH (labels are AND-ed)
lynk evals run -d core -d finance   # cases in either domain (domains are OR-ed)
lynk evals run -F smoke -d core     # "smoke" cases in the core domain
lynk evals run --max-concurrency 10  # default 5, capped at 20

--filter/-F and --domain/-d are both repeatable: multiple --filter values must all be present on a case's labels (AND), while multiple --domain values match a case in any of them (OR). validate also accepts -t/--test-case NAME to check a single case.

run goes further: it validates every selected case against the API before starting, and refuses to run at all if any case fails — a broken expected_sql would otherwise cost two agent runs and a judge call, then be scored against SQL that was never valid. A rejected run creates no run directory. That costs one cheap validation request per case up front.

Both commands check your dataset locally first — case names unique across files, and each case's domain and entities actually present in your .lynk source — but they react differently. validate reports every case: a case with a typo fails on its own (and is not sent), while the rest are still validated against the API, so one mistake never hides the state of the whole dataset. It exits non-zero if any case failed. run stops before sending anything if any case has a problem, because it is about to spend real agent time.

The local check is a typo catcher, not a guarantee: the agents see the compiled layer, so a name that exists in your source can still be missing from a build.

Each run writes its artifacts under .lynk/evals/runs/{timestamp}/: run.json (run metadata and counts) and raw.jsonl (one line per case, with every stage's raw response). Add .lynk/evals/runs/ to your .gitignore.

A run reports each case as it finishes, with a spinner for the ones still going, so a long run shows progress instead of sitting silent. It ends with a table of the scores each case got, one column per evaluator.

Cases that errored have no scores, so they appear in the list above the table but not in it — an infra failure is not a low score. run never exits non-zero for low scores or case errors; those are results, not failures. It exits non-zero only when a run could not start: no git repo, no dataset, a bad --max-concurrency, a pre-flight problem, or a case that failed validation. Aggregation across a run is not implemented, so each score is a single trial — small differences between cases are noise.

lynk marketplace

A command group for the Lynk plugins, distributed as a plugin marketplace. Every command names its coding harness explicitly — --harness claude is required, and claude is the only value today — and that harness's own CLI has to be on your PATH, since these commands drive it.

lynk marketplace install --harness claude (alias: lynk setup --harness claude) sets up the current project: it downloads the latest marketplace release to $HOME/.lynk/marketplace, registers it with Claude Code, installs the plugins it declares, and wires a SessionStart hook into the project's .claude/settings.json so the plugins stay current automatically. Start a new Claude Code session afterwards to load them.

lynk marketplace install --harness claude   # set up this project (same as `lynk setup`)
lynk marketplace update --harness claude    # refresh without waiting for a session start

lynk marketplace update --harness claude fetches the marketplace only when it has changed (conditional request), updates the installed plugins, and tells you to run /reload-plugins or relaunch when a new version lands. It prints nothing when everything is already current, and always exits 0 — a failed refresh (offline, expired login, missing claude) reports a warning and leaves the working installation in place, so it can never stop a session from starting. --hook is what the hook itself passes: it emits Claude Code SessionStart JSON on stdout, which Claude Code reads to tell you the plugins moved.

The marketplace lives at $HOME/.lynk/marketplace — machine-wide, not per project, because Claude Code keeps a single global marketplace-name → path mapping. The extracted release version is recorded in $HOME/.lynk/marketplace.release.

Commit .claude/settings.json (the hook plus your enabledPlugins) so everyone on the repo gets the same setup; keep the generated, machine-specific .claude/settings.local.json out of git.

Configuration

API token (non-interactive auth)

For CI and automation where a browser login isn't possible, authenticate with an API token instead of lynk auth login. Provide it with --api-token or the LYNK_API_TOKEN environment variable — it works on every command:

LYNK_API_TOKEN=lynk_… lynk build run        # via env var (best for CI)
lynk --api-token lynk_… build run           # global flag (before the command)
lynk build run --api-token lynk_…           # per-command flag (after the command)

When set, the token is sent as the x-api-key header on API requests, bypassing the OAuth session entirely. An API token is a secret, so it is read only from --api-token / LYNK_API_TOKEN — never from ~/.lynk/config.toml. It takes precedence over any stored browser login.

Tracing

The CLI reports a trace of each invocation to Lynk, and API calls carry the trace context so server-side spans join the same trace.

Set TRACEPARENT (a standard W3C traceparent) to have the CLI join a caller's trace instead of starting its own — useful when a CI job or wrapper script invokes lynk and wants its trace to include the invocation.

Troubleshooting

Symptom Fix
Not logged in / Session expired Run lynk auth login (or pass --api-token / set LYNK_API_TOKEN).
Authentication failed with an API token The --api-token / LYNK_API_TOKEN value is invalid or revoked — check it.
Could not determine the branch Pass -b <branch> or run from a git repo.
evals run/validate fails because no build exists for this commit Run lynk build local (or lynk build run) first.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lynk_cli-0.1.3.tar.gz (121.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lynk_cli-0.1.3-py3-none-any.whl (66.8 kB view details)

Uploaded Python 3

File details

Details for the file lynk_cli-0.1.3.tar.gz.

File metadata

  • Download URL: lynk_cli-0.1.3.tar.gz
  • Upload date:
  • Size: 121.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for lynk_cli-0.1.3.tar.gz
Algorithm Hash digest
SHA256 e72377b0405c2922265e7c0902e9228ee3bfed6e24d037bb9e7999efb28b52aa
MD5 24201263487f513094b11ee979466790
BLAKE2b-256 97647ad77c7c8e8a5119a1cb2d6088c744045f5bc629f054e06c45e14832a4b9

See more details on using hashes here.

File details

Details for the file lynk_cli-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: lynk_cli-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 66.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for lynk_cli-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 e7d8ddcbe702e029a95135e9ca037b9aecc32b9351fb6bb7d7453158054acc1e
MD5 78f46b110f137951fe5c47660f3e908f
BLAKE2b-256 a1099e8d964208ee0eb004a212e157bf6ac233a24afa7231cebc62c6f88f153b

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.5

2 files

0.1.4

2 files

This release

0.1.3 This release

2 files

0.1.2

2 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