CLI

The norcube / nrc command-line client — install, browser-based login, profiles, organization management, configuration, and self-upgrade.

Not verified yet

The Norcube CLI ships as one binary with two names — norcube and the short alias nrc. The platform-level commands are documented here; the product command groups have their own pages: LangSync CLI, Backup CLI and DomainRadar CLI, and the organization's billing is under nrc billing. Every command and flag is listed in the CLI reference, which is generated from the CLI's own help text.

Commands follow nrc <service> <resource> <verb> with plural resources: nrc backup jobs list, nrc langsync terms add. Names from earlier releases (nrc backup list, nrc langsync mark add, singular groups) keep working; set NORCUBE_DEPRECATION_WARNINGS=1 to see a note when a script uses one.

Global behaviour

Every command supports:

  • --profile <name>: use a named profile (environment, organization and session) instead of the default one.
  • --org <slug-or-id>: run against a specific organization without changing the profile's one.
  • -o, --output table|json|yaml|text: table (default, for people) or a format for scripts; see output and scripting.
  • --query <JMESPath>: filter or reshape the result before it is printed, in any format.
  • --no-pager: long tables normally page through less ($NORCUBE_PAGER / $PAGER override); this disables it.
  • --no-color: no color or styling (NO_COLOR and CLICOLOR=0 do the same; output that isn't going to a terminal is never colored).
  • --debug: print every HTTP request and response to stderr, with credentials redacted (same as NORCUBE_DEBUG=1); see troubleshooting.

The CLI also checks for new releases in the background (cached a day; disable with NORCUBE_NO_UPDATE_CHECK=1) and prints a one-line notice when an upgrade is available.

Login and identity

nrc login                # opens the browser; --force to re-authenticate
nrc login --no-browser   # prints the URL instead of opening a browser
nrc login --device       # approve on another device (your phone) with a code
nrc whoami               # who am I, which org and profile, which API host
nrc auth status          # does this profile's session still work? (exit code 4 if not)
nrc logout               # ends this profile's session; --all for every profile

login starts a loopback handshake: it opens app.norcube.com/cli-login in your browser, you approve while signed in, and the browser hands a separate CLI session back to the local process. Nothing to paste. The session is stored for the selected profile in your OS keyring (service name norcube — that's what the macOS Keychain prompt is about); see credential stores for machines without one. Short-lived access tokens are minted from it per product and organization automatically, including transparent refresh-token rotation.

Use --no-browser when the CLI can't open a browser for you (a remote desktop, a locked-down shell): it prints the URL, and you open it in a browser on the same machine. Only the configured web app may call the local login server.

Signing in from another device

nrc login and --no-browser need a browser on the same machine, because the browser hands the session to the CLI through 127.0.0.1. Over SSH, in a container, or when the only browser at hand is your phone, use device sign-in instead (CLI 0.18 and later):

$ nrc login --device
To sign in, open this page on any device (your phone works) and enter the code:

  https://app.norcube.com/device

  WDJB-MJHT

Only approve if you started this sign-in. Norcube never asks you for this code.
Waiting for approval… 9:55 left (Ctrl-C to cancel)

When the terminal can show one, the CLI also prints a QR code of the page with the code filled in.

Open the link on your phone or laptop, sign in to Norcube if you aren't already, and enter the code (case doesn't matter, the dash is optional). The page shows which device is asking (its name, the CLI version and operating system, the IP address it asked from, and when), so you can check that it's your terminal. Compare the code with the one in your terminal, then Approve. The CLI notices within a few seconds and finishes the sign-in; the session it gets is the same as a browser sign-in, listed under CLI sessions with that device's name.

A few things to know:

  • Only approve codes you started. Norcube never asks you for this code. If someone sends you a code or a /device link, deny it: approving would sign their CLI in to your account.
  • Codes expire after 10 minutes and work once. Deny stops the waiting CLI straight away; a denied or expired code exits 4.
  • Approving needs your dashboard session. A CLI's own token can't approve device sign-ins, so a leaked CLI session can't be used to sign in more machines.
  • Under the hood this is the OAuth 2.0 Device Authorization Grant (RFC 8628): the CLI polls Norcube Auth every few seconds and slows down when asked to.

Running several commands at once is safe. The session's refresh token rotates on use, so the CLI lets only one process refresh it at a time (through a lock file next to the config) and the others reuse the fresh token. Parallel CI steps and shell loops don't log you out.

Because the CLI session is independent of your browser session, logging out of the web app doesn't disconnect the CLI, and vice versa — nrc logout is what clears the CLI side. It ends the profile's session on Norcube, so its refresh token stops working everywhere, then removes the session and signed-in user from your machine. It keeps the profile itself, including its organization, so nrc login gets you back where you were. If Norcube can't be reached, logout still clears the machine and prints a warning; the session then ends after 30 days unused, or you revoke it under Account › CLI sessions. With -o json, the result's serverSessionEnded says whether the server call worked.

CLI sessions

Every nrc login creates a session you can see in the dashboard under Account › CLI sessions: the device name, the CLI version and operating system, when it signed in, when it was last used and from which IP address. Revoke signs that device out at once (or Revoke all for every device); the CLI there has to run nrc login again. A command running at that moment can finish its current request, since the access tokens it already holds last a few minutes. A session you don't use for 30 days ends on its own.

The same list is in the CLI:

nrc auth sessions list                 # * marks the session this CLI uses
nrc auth sessions revoke <session-id>  # sign one device out
nrc auth sessions revoke --others      # sign out everywhere but here

nrc logout ends the session the CLI on this machine uses. To end a session on a device you no longer have, revoke it from another device with nrc auth sessions revoke or in the dashboard. Revoking an unknown session id exits with code 3.

If a session ended elsewhere (revoked in the dashboard, signed out from another machine, or unused for 30 days), the next nrc login notices it, forgets the dead session, prints "Your previous session ended (revoked or expired); signing in again." and opens the sign-in. You don't need --force for that; --force is only for replacing a session that still works.

Login labels the session for you: the sign-in page receives this machine's hostname and the CLI's version, shows them before you approve, and stores them on the session. Sessions from older CLIs have no device name.

The session also protects you if its refresh token leaks. Each refresh replaces the token, and if an old one is ever used again (the thief's copy or yours), Norcube ends the whole session, so both copies stop working and you sign in again. A retry within a few seconds of a refresh doesn't count, so flaky networks don't sign you out.

Tokens for scripts

nrc auth status --all-profiles                 # who is signed in where
curl -H "Authorization: Bearer $(nrc auth token --audience langsync)" …
nrc auth token --audience langsync -o json     # {accessToken, audience, organization, expiresAt}

nrc auth status asks Norcube Auth whether the profile's stored session still works. Its SIGNED IN column (session in JSON) is one of:

SIGNED INJSON sessionMeaningExit code
yesactiveThe session works.0
nononeNothing is stored for the profile. Run nrc login.4
revoked/expiredendedNorcube ended the session: revoked, signed out elsewhere or unused 30 days.4
unknownunknownNorcube Auth couldn't be reached; the reason goes to stderr.0

A cached access token that hasn't expired counts as yes without a request, because it was issued from the session within the last few minutes, so checking doesn't rotate the refresh token for nothing. --offline skips the check and only looks at the stored credentials. With --all-profiles, every profile is checked in parallel and the command always exits 0.

nrc auth token prints a short-lived access token (valid for a few minutes) for one service and organization: --audience is one of auth (the default), backup, billing, domainradar, langsync or prompthub, and the organization comes from --org or the profile. The token acts as you in that organization, so treat it like a password; the CLI warns when it prints one to a terminal. With a CI token, the token is minted from it for the token's organization; auth has no CI token equivalent.

CI and automation

A CI job shouldn't run as a person. Give it a CI token: a secret that belongs to one organization, carries only the scopes you choose, always expires, and keeps working when whoever created it leaves the organization. Available from CLI 0.18; CI tokens covers scopes, expiry, rotation and how they're secured.

# with your own login, once:
nrc auth ci-token scopes                 # what a token can do, and what your role may grant
nrc auth ci-token create --name "GitHub Actions" --scopes langsync.sync --expires 90d
nrc auth ci-token list                   # status, expiry, last use
nrc auth ci-token revoke "GitHub Actions"

create prints the secret (nrc_ci_…) once; Norcube keeps only a hash. With -o text it prints nothing else, so it can go straight into a secret store:

nrc auth ci-token create --name deploy --scopes langsync.sync -o text | gh secret set NORCUBE_TOKEN

--expires takes 12h, 90d, 4w or a date such as 2027-01-31 (default 90 days, at most 366). You can only grant scopes your own role allows. The same tokens are under IAM › CI tokens in the dashboard.

In the job, set the secret as NORCUBE_TOKEN and run commands as usual:

NORCUBE_TOKEN=nrc_ci_… nrc langsync sync

How the CLI uses it:

  • It checks the token's checksum locally, so a truncated or mistyped secret fails at once (exit 2) instead of at Norcube.
  • It exchanges the token for a short-lived access token per service and keeps those in memory only; nothing is written to disk or a keyring.
  • The organization is the token's own. --org, NORCUBE_ORG or a project's .langsync.json naming another organization is an error (exit 2), so a job can't quietly act elsewhere.
  • A revoked or expired token exits 4; a token without a scope for the service exits 5 and names the service.
  • nrc auth status shows the token's organization, scopes and expiry; commands that act as a person (whoami, org …, auth sessions …) explain that they need nrc login.

GitHub Actions

jobs:
  translations:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: norcubeplatform/setup-norcube@v1
        with:
          token: ${{ secrets.NORCUBE_TOKEN }}
      - run: nrc langsync sync --strategy local --wait=false

norcubeplatform/setup-norcube installs the CLI from the official release after checking it against the release's SHA-256 checksums, adds norcube and nrc to PATH and exports the token as NORCUBE_TOKEN (masked in logs). Pin version: for reproducible builds.

GitLab CI

translations:
  image: debian:bookworm-slim
  variables:
    NORCUBE_NO_UPDATE_CHECK: '1'
  before_script:
    - apt-get update -qq && apt-get install -yqq curl ca-certificates
    - curl -fsSL https://github.com/norcubeplatform/cli/raw/main/install.sh | sh
    - export PATH="$HOME/.norcube/bin:$PATH"
  script:
    - nrc langsync sync --strategy local --wait=false
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Store the token as a masked, protected CI/CD variable named NORCUBE_TOKEN.

Give each pipeline its own token with the narrowest scopes it needs, so revoking one doesn't stop the others, and create a new one before the old one expires.

Organizations

nrc org list                 # all your orgs; * marks the profile's org
nrc org use <slug-or-id>     # set the profile's organization
nrc org switch               # interactive picker
nrc org current              # print the profile's organization
nrc org create "Acme Inc" [--slug acme] [--set-active=false]

Each profile has an organization that every product command targets by default. org use sets it for the selected profile, whoami shows it, and --org (or NORCUBE_ORG) overrides it for one command. Both take a slug or an id. A slug is looked up among your organizations and the result is cached for 24 hours; a slug you don't belong to fails with exit code 2 before any request is made. Sensible scripting default: org create auto-activates the new org in interactive shells but not in scripts, so automation never silently changes your state — pass --set-active explicitly to choose.

Note that LangSync project directories can pin their own organization via .langsync.json, which beats the profile's organization inside that tree (--org and NORCUBE_ORG still win) — see org resolution.

Profiles

Most people never need a profile: nrc login signs you in to the profile default, and every command uses it. A profile is a named organization and session, like AWS CLI profiles, for keeping several accounts or organizations side by side: an agency working in a client's account, or a CI job with its own sign-in.

nrc login                                 # profile "default"
nrc configure --profile client-acme       # pick the organization for a second profile
nrc login --profile client-acme           # a separate session for it
nrc backup jobs list --profile client-acme
NORCUBE_PROFILE=client-acme nrc whoami
nrc config profiles                       # list profiles; * marks the selected one
nrc logout --profile client-acme          # or: nrc logout --all

The selected profile is --profile, else NORCUBE_PROFILE, else default_profile in the config file, else default. Logging in to a profile that doesn't exist yet creates it.

nrc configure asks for the selected profile's organization and where to keep its session (creating the profile if needed). Single settings change with configure set|get|unset <key> [value]:

KeyApplies toValues
environmentselected profileproduction (default) or custom (see below)
organizationselected profileslug or id of the organization commands target
credential_storeselected profilekeyring, file or env
outputselected profiletable, json, yaml or text
endpoints.<service>selected profileURL override for one service
default_profilethe whole fileprofile used when no profile is selected otherwise
defaults.<setting>every profileoutput, pager, max_attempts, read_timeout, connect_timeout

The services are auth, web_app, snapdb, langsync, domainradar, billing and prompthub.

Advanced: custom endpoints

Profiles talk to Norcube's production endpoints. If you reach Norcube through a proxy or another gateway, set environment = "custom" and list the endpoints with nrc configure set endpoints.<service> <url>; services the profile doesn't list fall back to production. For a single command, --endpoint-url service=url or NORCUBE_<SERVICE>_URL overrides one endpoint. A profile holds one session for one set of endpoints, so login refuses to replace a profile's session with one from other endpoints; use a separate profile for them.

Precedence

What a command uses, highest precedence first:

SettingOrder
Profile--profile › NORCUBE_PROFILE › default_profile › default
Organization--org › NORCUBE_ORG › project file (.langsync.json) › profile organization
Endpoints--endpoint-url service=url (and --auth-url, --web-app) › NORCUBE_<SERVICE>_URL › profile endpoints › production
Credentials--token-file › NORCUBE_TOKEN › profile credential_store › OS keyring
Output-o › NORCUBE_OUTPUT › profile output › [defaults] output › table

nrc config list (alias config show) prints every effective value and where it came from — the answer to "why is the CLI hitting the wrong host?".

Credential stores

  • keyring (default): one item per profile in the OS keyring (Keychain, Secret Service, Windows Credential Manager), holding the refresh token and cached access tokens. The session is tied to the profile's auth endpoint, so a session is never sent to other endpoints.
  • file: credentials/<profile>.json next to the config file, in files readable only by you (0600, in a 0700 directory). When no keyring is available (containers, CI, SSH without D-Bus) the CLI uses this store automatically and says so once; set credential_store = "file" to choose it explicitly and silence the notice.
  • env: a CI token or an access token in NORCUBE_TOKEN. Nothing is stored. --token-file <path> reads the token from a file instead and works with any profile.

Configuration

nrc config list          # effective settings and their sources
nrc config profiles      # the profiles in the config file
nrc config path          # where the config file lives
nrc config edit          # open it in $VISUAL or $EDITOR
nrc config reset-urls    # remove the selected profile's endpoint overrides

The config file is config.toml in $XDG_CONFIG_HOME/norcube/ when XDG_CONFIG_HOME is set (on every OS), else your user config directory: ~/.config/norcube/ on Linux, ~/Library/Application Support/norcube/ on macOS, %APPDATA%\norcube\ on Windows. A config that already lives in the macOS or Windows directory keeps being used even when XDG_CONFIG_HOME is set. NORCUBE_CONFIG_FILE names the file directly. It never holds tokens.

schema_version = 2
default_profile = "work"

[defaults]
output = "table"
max_attempts = 3
read_timeout = "60s"

[profiles.work]
environment = "production"     # production (default) | custom
organization = "acme"          # slug or id; the CLI records org_id after resolving it
credential_store = "keyring"   # keyring | file | env

[profiles.client-acme]
organization = "client-acme"

[profiles.gateway]
environment = "custom"         # services not listed fall back to production
[profiles.gateway.endpoints]
auth = "https://norcube-auth.gateway.example.com"
langsync = "https://norcube-langsync.gateway.example.com"

[profiles.ci]
organization = "acme"
credential_store = "env"       # takes an access token from NORCUBE_TOKEN

The CLI writes the file atomically with 0600 permissions and keeps keys it doesn't know (comments are not preserved). Upgrading from a CLI version without profiles converts the old flat file into a default profile automatically, keeps a config.toml.bak-<time> copy, and carries your session over, so you stay signed in. The first command that uses the session moves it into the profile; an older CLI still installed on the same machine then asks you to sign in again rather than reuse a token that was already rotated.

The refresh lock files live next to the config file, in locks/. The slug cache (norcube/orgs.json in your user cache directory, per profile) holds no secrets, and nrc logout clears it.

Environment variableFlagMeaning
NORCUBE_PROFILE--profileProfile to use.
NORCUBE_ORG--orgOrganization for this command (slug or id).
NORCUBE_OUTPUT-o, --outputtable, json, yaml or text.
NORCUBE_ERROR_FORMATnonejson writes every error as JSON on stderr, whatever the output format.
NORCUBE_TOKEN--token-fileUse this access token instead of the profile's session.
NORCUBE_CONFIG_FILEnonePath of the config file.
NORCUBE_<SERVICE>_URL--endpoint-url service=urlOverride one service's endpoint (NORCUBE_SNAPDB_URL, NORCUBE_LANGSYNC_URL, …).
NORCUBE_AUTH_URL--auth-urlOverride the Norcube Auth endpoint.
NORCUBE_WEB_APP--web-appOverride the web app used for browser login.

Network settings

Every request has timeouts, and requests that are safe to repeat are retried with backoff when the API is throttling (429), briefly unavailable (502, 503, 504) or the network drops. A Retry-After header is honored. Flags win over environment variables, which win over [defaults] in the config file.

Environment variableFlagDefaultMeaning
NORCUBE_READ_TIMEOUT--cli-read-timeout60Seconds to wait for each API response, 0 for no limit. Downloads fail after 60 s without data.
NORCUBE_CONNECT_TIMEOUT--cli-connect-timeout10Seconds to wait for a connection, 0 for no limit.
NORCUBE_MAX_ATTEMPTS--max-attempts3Attempts per request; 1 disables retries.
NORCUBE_CA_BUNDLEnonenonePEM file of extra CA certificates to trust, for TLS-inspecting proxies.

HTTPS_PROXY and NO_PROXY are honored. Requests carry a User-Agent of the form norcube/<version> (<os>; <arch>) go/<version>.

Output and scripting

Every command prints its result in the format -o picks:

FormatWhat you get
tableAligned columns, or a short sentence for actions. For people; pages through $PAGER on a terminal.
jsonThe resource itself: lists are arrays, field names are the API's own. Actions (create, delete, pause …) return what they changed.
yamlThe same data and field names as json.
textTab-separated values without a header, one record per line, for cut, awk and shell loops.

Tables show times in your local time zone. -o text prints them as RFC 3339 in UTC, and json and yaml keep the API's own values.

--query takes a JMESPath expression and applies it to what -o json would print, before formatting, so it combines with every format:

nrc backup jobs list -o json --query "[?jobStatus=='failed'].jobId"
nrc backup datasources list -o text --query "[?!isActive].id"
nrc whoami -o text --query user.email
nrc org list --query "[].{slug: slug, active: active}"   # a table of just these columns

An invalid expression fails with exit code 2 before any request is made. backup datasource list filters by name with --search (its old --query flag became the JMESPath filter).

stdout is data, stderr is everything else. Progress bars, the langsync sync dashboard, prompts, confirmations and hints go to stderr, so nrc … -o json | jq always gets clean JSON. sync, pull and init print one summary per namespace with -o json, yaml or text; with -o table the dashboard is the output.

Lists. Paginated lists take --page-size (alias --limit), --cursor, --all-pages and --max-items, and print as plain arrays. When more results exist the next cursor goes to stderr: a sentence in table output, nextCursor=<cursor> otherwise.

Errors. On a terminal an error is the message with a hint below it. With -o json or -o yaml, or NORCUBE_ERROR_FORMAT=json, stderr gets one JSON object instead:

{
  "error": {
    "code": "not_found",
    "message": "data source not found",
    "status": 404,
    "service": "backup",
    "method": "GET",
    "url": "https://snapdb.api.norcube.com/app/v1/datasources/9f8e…",
    "type": "NOT_FOUND",
    "requestId": "…"
  }
}

code is one of usage_error, validation_failed, org_not_found, not_found, login_required, permission_denied, insufficient_scope, rate_limited, timeout, conflict, server_error, interrupted, job_failed or error. Quote requestId when you contact support.

Waiting for jobs. Commands that start a job on the server take --wait to follow it to the end: backup jobs run, backup restores create, backup restore-tests run, langsync terms import (and terms import status), domainradar bulk create, domainradar names generate and domainradar names check. When the job then fails (or, for DomainRadar, is cancelled), the command exits 1 with the code job_failed and the job as it was last seen under details, so a script can tell "the job failed" from "the CLI failed". For a restore test, anything but a pass counts as failed. Ctrl-C stops waiting, not the job, and --wait-timeout gives up waiting with exit code 7 while the job keeps running. Before CLI 0.20, the DomainRadar commands exited 0 on a failed or cancelled job.

Calling any API: nrc api

For an endpoint the CLI has no command for yet, nrc api sends the request with the profile's credentials, organization, timeouts and retries, and prints the JSON answer (so -o and --query work):

nrc api backup GET /datasources
nrc api domainradar POST /check -f domain=example.com --org acme
nrc api domainradar /check/bulk --paginate --query "list[].id"
nrc api langsync POST /namespaces --input namespace.json

The service is backup, langsync, domainradar, billing or prompthub, and the path is relative to that service's API base URL. -f key=value adds a string field, -F key=value a typed one (true, false, null, a number, or @file); fields become query parameters on GET, HEAD and DELETE and a JSON body otherwise, and switch the default method to POST. --paginate follows the API's cursor and merges the arrays of every page. The CLI sets Authorization itself and refuses absolute URLs, so the token never goes to another host.

Shell completion

norcube completion zsh > "${fpath[1]}/_norcube"
norcube completion bash > /etc/bash_completion.d/norcube
norcube completion fish > ~/.config/fish/completions/norcube.fish

Homebrew installs these for you. They register for the norcube command; to complete the nrc alias too, add compdef nrc=norcube (zsh) or complete -o default -F __start_norcube nrc (bash) to your shell profile.

Besides commands and flags, Tab completes organization slugs (--org, org use), profile names, Backup data source and job ids, and LangSync namespaces and language codes. Those come from the API with a one-second budget and are cached for a minute per profile and organization (in the user cache directory, under norcube/completion); when a lookup fails, completion simply offers nothing.

Troubleshooting

nrc doctor checks everything that usually explains a failing command and exits 1 when a check fails:

nrc doctor                 # every check
nrc doctor --offline       # skip the network checks
nrc doctor -o json         # attach to a support request: no secrets

It reports the CLI version (and a newer release, if any), the config file (readable, valid, permissions 0600), which profile and organization apply and why, the credential store, proxy and CA bundle settings, DNS, TLS and latency of every service endpoint, clock skew against Norcube Auth, the session, and whether a token can be minted for every service in the target organization.

--debug (or NORCUBE_DEBUG=1) prints each HTTP attempt to stderr: method, URL, headers, small JSON and form bodies, status, timing and the request id. Authorization keeps only its scheme, cookies and API keys are replaced, and token, secret, password, key, credential and signature fields are redacted in URLs and bodies, including presigned download links. Downloads and streams are never buffered.

Upgrading

nrc upgrade              # self-update from GitHub releases

The updater verifies the release's SHA-256 checksum before swapping the binary, and it's package-manager aware: a Homebrew-installed norcube tells you to brew upgrade norcube instead (override with --force).

Errors you'll actually see

MessageMeaning
"Not signed in. Run norcube login."The profile has no CLI session; the hint names --profile if needed.
"no active organization. Run norcube org use <slug> or pass --org"The profile has no organization and no --org was given.
"no organization "acme" among the ones you belong to"The --org slug isn't one of your orgs.
"you're not a member of organization …"Signed in, but that org isn't yours.
"login timed out after 5m0s"The browser handshake wasn't completed in time.
"Installed via Homebrew — run brew upgrade norcube instead."Self-update deferred to your package manager.

Exit codes

Scripts can branch on the exit code:

CodeMeaning
0Success.
1Error: network, server, or a failed operation, including a job that failed while the command waited for it (--wait, code job_failed).
2Usage or validation error: unknown command or flag, wrong arguments, invalid --query, unknown --org slug, a prompt without a terminal.
3Not found: the API answered 404.
4Not signed in, or the session expired. Run nrc login (with --profile).
5Permission denied: not a member of the organization, or missing a permission or OAuth scope.
6Still rate limited after the retries.
7Timed out.
8Conflict with the current state: the API answered 409.
130Interrupted (Ctrl-C or SIGTERM). A second Ctrl-C stops the process at once.

On this page