Operator reference for nicocli, the CLI for the NICo REST API. Covers installation, configuration, authentication, command mechanics, output formatting, debugging, and TUI mode. Targeted at operators who have completed the Quick Start Guide and want to drive NICo from scripts or one-off interactive sessions.
The Day One Operations guide uses this reference for all CLI mechanics. Read this page first if you plan to script anything beyond the Quick Start happy path.
Build and install from the infra-controller-rest repo:
Verify:
If nicocli is not on $PATH, add $(go env GOPATH)/bin to it.
Note on CLI naming: older docs and shipped binaries reference
carbidecli(built viamake carbide-cli). It’s the same source under a previous name; the binary was renamed during the transition from carbide-core to NICo. The Makefile retains bothmake nico-cliandmake carbide-clitargets. Prefernicoclifor new work.
Default: ~/.nico/config.yaml. Create one with nicocli init (errors if a file already exists). Override the path per-command:
The config is written with 0600 permissions (private to the owning user). nicocli writes tokens and refresh tokens back to the active config on every successful login or auto-refresh, so the permissions matter.
The TUI auto-discovers any file matching ~/.nico/config*.yaml. Use one file per environment, naming the file after the environment so the picker is self-documenting:
For non-interactive commands, pass --config <path>. For TUI, start nicocli tui and pick from the list.
api.base, api.org, api.nameapi.name is the most common source of misconfiguration. If every command returns:
your api.name does not match the deployment. Find the deployment’s expected value in the API server’s running config (the api.name key in the carbide-rest-api configmap for carbide-rest-namespace deployments) and set it in your config.
nicocli init writes a fully commented template — start from that rather than copying the snippet above by hand.
nicocli login runs the appropriate auth flow and saves the resulting bearer token back to the active config. Pick the method that matches your deployment.
When you run nicocli login, nicocli decides which flow to use in this order:
--token-command flag (overrides everything; persists auth.token_command to config).--api-key / --authn-url flags.--token-url / --client-secret / --username / --password / --keycloak-url flags.auth.token_command in config.auth.oidc in config.auth.api_key in config.If your config is set up correctly, plain nicocli login picks the right method. The flag forms below are mostly useful for first-time setup and CI scripts.
For short interactive sessions or when token issuance is handled outside nicocli:
No nicocli login is needed — the token is used directly. When it expires, paste a fresh one or move to token_command.
When your auth provider’s token semantics do not match nicocli’s built-in OIDC grants — for example, when the provider requires a custom OAuth scope, an mTLS-fronted token endpoint, or a wrapper that fetches credentials from a secret store — write a small script that prints a bearer token to stdout and reference it from config:
Or for a one-shot login that also persists token_command to the config:
After login, every subsequent nicocli command re-runs the script when the cached token is near expiry. The bearer token is redacted in --debug output, but the path to the script is visible in the config.
The script must:
Minimal example — adapt the curl payload and headers to whatever your provider requires:
chmod 700 the script — it’s invoked on every token refresh.
For deployments backed by Keycloak (or any OIDC IdP that supports the standard password or client-credentials grants), put the token URL and client identity in config:
Then:
Keycloak shorthand (constructs the token URL automatically as <keycloak-url>/realms/<realm>/protocol/openid-connect/token):
The default realm is nico-dev; override with --keycloak-realm or NICO_KEYCLOAK_REALM.
After login, the access token, refresh token, and expiry time are saved back to the config. The TUI auto-refreshes tokens 30 seconds before expiry and retries failed requests on 401 Unauthorized up to three times.
OIDC scope is hardcoded: the built-in password and client-credentials grants both send
scope=openid— this is not configurable. If your IdP requires a different scope, useauth.token_commandinstead.
For NGC-backed deployments:
Keys prefixed with nvapi- are bearer tokens directly — no authn_url is required. Legacy NGC API keys without the prefix must be exchanged via the authn_url:
The CLI errors clearly if authn_url is missing on a legacy key. nvapi- keys never need it.
Every auth flag has a corresponding env var, useful for CI/CD pipelines:
After login, confirm nicocli can reach the API and your identity is correct:
user get returns the authenticated identity as NICo sees it. Service accounts have blank email/firstName/lastName; human users have those populated from the IdP.
nicocli commands are generated from the OpenAPI spec. Each tag becomes a top-level resource; each operation becomes an action under it:
Examples:
Some resources have sub-resources — a third grouping level. Constraints under allocations are a typical case:
Run nicocli <resource> --help to enumerate available actions and sub-resources for any tag.
The CLI’s action-name resolver collapses get-current-X operation IDs to a short get action when there’s no sibling collision. When two operation IDs would collide on the short form, both keep their full names.
Use --help to confirm the actual action name for any resource if you’re unsure.
Flags MUST come before positional arguments. nicocli uses urfave/cli, which stops parsing flags at the first positional. Examples:
When the ordering is wrong, the CLI prints a clear error:
--data vs flag formsMost create and update operations expose every body field as an individual flag. Prefer the flag form — it’s shorter and gets validated up front. For example:
Use --data '<json>' or --data-file <path> (use - for stdin) only when:
interfaces[], sshKeyGroupIds[], allocationConstraints[], nvLinkInterfaces[], and similar arrays cannot be set through individual flags — they go through the body.get -o json -> edit -> update --data-file.JSON bodies use camelCase (siteId, vpcId, ipv4BlockId) — the same as the REST API request bodies. Flag names are kebab-cased mechanically, which is not always invertible. Two gotchas:
ipv4BlockId -> --ipv4block-id, not --ipv4-block-id.vniId -> --vni-id; nvLinkLogicalPartitionId -> --nv-link-logical-partition-id.When in doubt, run <command> --help to see the exact flag name.
--outputList and get commands support --output <format>:
The detail (get <id>) view is always richer than the list view — list endpoints often omit nested objects for performance. If list doesn’t show a field you need, get likely will.
List commands accept --page-size, --page-number, and --all:
When results span multiple pages, a one-line pagination summary is printed to stderr above the data:
When piping to jq, suppress the summary with 2>/dev/null:
--all follows pagination links automatically (capped at 1000 pages). For very large result sets, paginate explicitly to stay within memory budgets.
--queryList endpoints expose dedicated filter flags derived from the OpenAPI spec. For example, nicocli allocation list --help shows --site-id, --tenant-id, --resource-type, --resource-type-id, --status, --constraint-type, --constraint-value, --include-relation, --order-by, plus the standard pagination flags. Use those.
The --query flag is a free-text search across name, description, and status fields — it is NOT a key=value filter. --query "resourceType=InstanceType" matches the literal substring resourceType=InstanceType in those fields, which is almost never what you want. Reach for the dedicated flags.
--debugThe global --debug flag logs the full HTTP request and response for the wrapped command. The bearer token is redacted; everything else is visible:
Use it for:
api.name segment.--data debugging).api.name rewritingnicocli substitutes the API name segment in every URL before sending. The OpenAPI spec uses nico as the placeholder; the deployment may use any value its operators chose. nicocli rewrites /v2/org/<org>/nico/... to /v2/org/<org>/<api.name>/... transparently. --debug shows the rewritten URL, which is what you should see in the API server’s access log.
The CLI is generated from the OpenAPI spec at build time; the server reports its own image version (visible as apiVersion on audit responses). The two version schemes are independent — mismatches are normal and rarely matter, as the wire protocol is stable across patch and minor releases.
For exploratory work and one-off operations, the TUI is the recommended interface:
Behavior:
config*.yaml in ~/.nico/ and presents them as a selection list at startup.allocation create only shows instance types and IP blocks that belong to the selected site, which avoids the common mistake of cross-site allocations.401 Unauthorized up to three times.The TUI’s interactive forms for create commands prompt for fields in order with type-aware pickers. For first-time operators this is significantly easier than constructing JSON bodies by hand. For scripts and automation, fall back to the non-interactive command form.
issuers block that maps OIDC IdPs to NICo.