---
title: License the runtime
description: "Where ClikaRT and Modelverse read the credential your platform issues, per language and packaging, and what a refused call looks like."
---

Every ClikaRT runtime needs a credential your platform issued for the project it ships under, and Modelverse, which runs on the same runtime, needs the same one. [Runtime licenses](/platform/concepts/runtime-licenses) is the concept page: why the credential exists, [the two kinds](/platform/concepts/runtime-licenses#the-two-kinds) (an online key, an offline bundle), the entitlements it carries, and [its lifecycle](/platform/concepts/runtime-licenses#lifecycle). This page is the runtime side of that loop: where the runtime looks for the credential, how to put it there from each language and packaging, and what a refused call carries.

## Where the runtime reads the credential

The runtime looks in three places, in this order, and uses the first one it finds:

1. The environment variable `CLIKA_RT_LICENSE`, holding either the credential text itself or the path of a file that holds it.
2. The environment variable `CLIKA_LICENSE`, in the same two forms.
3. The per-user file `~/.clika/runtime/license` (on Windows `%USERPROFILE%\.clika\runtime\license`), which `clikart-license-init <credential>` writes once; the tool also takes the credential from a file with `--from-file <path>`, and prompts for it on standard input when given neither, which keeps it out of your shell history. It ships in the bundle's `bin/` and as a console script of the `clika-runtime` Python wheel.

   The tool writes the file readable by its owner alone and prints the file's path, the credential's kind (an online license's carrier bundle, which the platform validates on first use, or a signed offline bundle with its project and its expiry) and the permissions it set. It refuses to replace a file that is already there, so a second run asks for `--force` rather than overwriting what a machine is running on.

The credential is the `CLIKA1-...` license key or license bundle your project's Licenses page reveals. A bare `clika_rk_...` API key is not a runtime credential and is refused everywhere, the license-init tool included.

```bash
export CLIKA_RT_LICENSE=/path/to/credential                  # a file holding the credential
export CLIKA_RT_LICENSE="$(cat /path/to/credential)"         # or the credential text itself
"$CLIKART_BUNDLE_DIR"/bin/clikart-license-init <credential>  # or the per-user file, once per user
```

Put it in place before the program starts.

## Set it from each language

<LangTabs>

<LangTab value="cpp">

A C++ program carries no code for the credential. The runtime reads the process environment, so set the variable in the shell, the service unit or the launcher that starts the program, or run `clikart-license-init` once on the machine and rely on the per-user file.

```bash
export CLIKA_RT_LICENSE=/path/to/credential
./my_program
```

</LangTab>

<LangTab value="python">

The `clika-runtime` wheel loads the runtime at import, so the variable is set before `import clika_runtime`: in the shell that starts Python, or in `os.environ` at the top of the program.

```python title="licensed.py"
import os

os.environ["CLIKA_RT_LICENSE"] = "/path/to/credential"  # before the import: the wheel loads the runtime here

import clika_runtime as crt

x = crt.tensor([1.0, 2.0, 3.0])
```

The wheel also installs `clikart-license-init` as a console script. After `clikart-license-init <credential>` has written the per-user file, the program needs no variable at all.

</LangTab>

<LangTab value="kotlin">

On Android there is no home directory for a per-user file and no `bin/` for the tool, so the credential arrives through the loader itself. `ClikaRtAndroid.load` takes it as its `license` argument; an explicit value wins over an ambient variable, and `null`, the default, leaves the environment alone.

```kotlin title="LicensedApp.kt"
import android.app.Application
import io.clika.runtime.ClikaRtAndroid

class LicensedApp : Application() {
    override fun onCreate() {
        super.onCreate()
        // readCredential() is the app's own: it returns the text the platform
        // revealed, from wherever the app keeps its secrets.
        ClikaRtAndroid.load(this, license = readCredential())
    }
}
```

`ClikaRtAndroid.load` also hands the runtime the app's Context, which is how the license identifies the device from inside an app (the identity Android scopes to the app). A command the app launches instead, such as the runtime's own command line, has no Context: set `XDG_CACHE_HOME` (or `HOME`) to a directory of the app in the child's environment, and the runtime keeps a per-installation identity there. A credential with a hardware seat budget refuses a process that can identify neither the device nor its installation.

On a desktop JVM, `ClikaRt.load()` needs nothing extra: the runtime reads the process environment, as in the C++ tab.

</LangTab>

</LangTabs>

## What a refusal looks like

A call the runtime may not serve fails through the three channels every runtime failure carries ([Handle errors by code](handle-errors-by-code.mdx)): the coarse status, a message, and the stable code name. The code name is `LICENSE_EXPIRED` when the credential's lifetime has run out and `LICENSE_FAILED` for every other refusal. It reads the same in every language, so branch on it, never on the message. A credential that lacks a grant refuses the call that needs it, with the code the [entitlements](/platform/concepts/runtime-licenses#entitlements) section lists.

The coarse status on a licensing refusal reads `Internal`, whose usual policy is to log everything and file a report, which is the wrong reaction to an unset variable. Read the code name first; [Handle errors by code](handle-errors-by-code.mdx) shows the captured refusal and the branch.

## Online and offline

An online key needs a route from the runtime to the platform; an offline bundle is verified locally against Clika's signature and needs none. Which to issue, and how each is revoked, is the concept page's [Lifecycle](/platform/concepts/runtime-licenses#lifecycle) section.

## Containers and CI

Pass the credential through the environment of the service, never through the image. A `docker run -e`, an orchestrator secret exposed as an environment variable, or a CI job's secret variable all reach the runtime as the variable above; a credential written into an image layer travels with every copy of that image. Keep it out of logs the same way: log a refusal by its code name, and never echo the variable's value.

```bash
docker run --rm -e CLIKA_RT_LICENSE="$CLIKA_RT_LICENSE" my-image
```

Issuing, revealing, rotating and revoking a credential is platform work: [Runtime licenses](/platform/concepts/runtime-licenses) is the concept and [the licensing commands](/platform/cli/licensing) drive it from the command line. [Quick install](../getting-started/installation.md) lists the credential among ClikaRT's prerequisites, and [Modelverse's quick install](/modelverse/getting-started/installation) among its own. `clikart-cli` runs on this runtime and reads the credential from the same places.
