Skip to content

License File

How the CodeCharter CLI locates and validates its license file, and which error messages can occur.

Every CLI archive downloaded from the customer portal can include a file named codecharter.license. It is a signed JWS token that ties the download to the customer who triggered it. Without a valid license the CLI refuses to start and exits with exit code 6.

Downloading with or without a license

On the Downloads page you will find two buttons per asset:

  • Download with license delivers the archive with your personal codecharter.license already embedded. This is the fastest option and is sufficient as long as the same account owns both the download and the CI workflows.
  • Without license delivers the generic, customer-agnostic archive without an embedded license. Useful if you mount the license separately from a secret store in your CI/CD pipeline, maintain an internal mirror, or want to decouple the build deterministically from a customer identity.

Both variants require an active subscription. The only difference is whether the license is included in the archive; the CLI itself is identical.

Not bound to a machine

The license file is not tied to any device. There is no activation step, no activation counter, and no hardware fingerprint — validation is a pure offline signature check. You can copy the same codecharter.license to as many machines as the seat terms of your plan cover; this is exactly how you roll CodeCharter out to a team. See What counts as a developer seat.

Where the CLI looks for the license

The CLI checks the following paths in order and uses the first file it finds:

  1. The path passed via --license <path>.
  2. The environment variable CODECHARTER_LICENSE (must be a file path to a license file, not the token content; the file itself can have any name).
  3. codecharter.license next to the CLI binary.
  4. codecharter.license in the current working directory.
  5. $XDG_CONFIG_HOME/codecharter/codecharter.license (Linux/macOS).
  6. %APPDATA%\CodeCharter\codecharter.license (Windows).
  7. $HOME/.config/codecharter/codecharter.license (fallback for Unix systems without XDG_CONFIG_HOME).

The simplest option: copy codecharter.license from the downloaded archive next to the CLI binary. All invocations will then work without any additional configuration.

Automatic renewal in CI (API key)

In CI you usually do not download a license at all. Instead you store your portal API key as a CI secret (CODECHARTER_API_KEY). On startup the CLI mints a short-lived license (24h by default) from that key and caches it in the per-user config directory (path 5/6/7 above), renewing it automatically as it nears expiry. The lifetime is always capped at your subscription's end date, so close to the end of a subscription the minted license can be valid for less than 24h. There is no daemon and nothing to schedule: a fresh runner fetches one license, a long-lived runner refreshes only when the cached one drops below one hour of remaining validity.

This keeps the API key as the only long-lived secret. A leaked cached license expires within 24h on its own, and revoking the key in the portal disables every license derived from it within the same window — no key rotation required.

Renewal authenticates with the API key only. The existing license file is never sent back to the portal, so a leaked codecharter.license cannot be used to obtain a fresh one.

If the portal is briefly unreachable while a still-valid license is cached, the CLI keeps using it until it actually expires (fail-open) and prints a warning, so a transient network blip does not break the build.

Two overrides are always respected and never touched by renewal: a path passed via --license and the CODECHARTER_LICENSE environment variable. Use those to pin a specific file; the CLI only ever writes to the managed cache location.

Renewal talks to https://codecharter.tools by default. If you run an internal mirror of the portal, set the CODECHARTER_PORTAL_URL environment variable to its base URL and renewal will use that instead.

Offline or long-lived runners

A runner without access to codecharter.tools cannot renew. Give it a full codecharter.license from the portal instead: the Downloads page has a Download codecharter.license button that serves just the token as a file. Place it on one of the search paths or point CODECHARTER_LICENSE at it. The CLI decides purely on remaining validity, not on how the license was obtained: as long as the file has more than one hour of validity left, the API-key path is never entered.

Keep in mind that a full license is only valid until the end of your current billing period. On a monthly plan that means it expires within at most a month and must be re-downloaded after each renewal. For runners that live longer than one billing cycle and have network access, prefer the CODECHARTER_API_KEY auto-renewal described above; reserve the standalone license file for genuinely offline machines.

What is validated

At startup of every gated subcommand (analyze, validate, init, lsp, docs, test, restore, update, verify, push, mcp install, and the mcp server itself) the CLI performs the following checks:

  • The file can be read.
  • The content is a valid JWS token with alg: RS256.
  • The signature matches one of the public keys embedded in the binary. During a key rotation the binary knows several keys simultaneously.
  • The exp claim (expiry date) is in the future. The check tolerates up to five minutes of clock skew.
  • Optional min_ver/max_ver claims do not exclude the running CLI version.

If any of these checks fails, the CLI exits with exit code 6 and writes a short diagnostic to stderr.

Common error messages

No codecharter.license file found

None of the search paths contained a license file. Re-download the current archive from the portal and copy codecharter.license next to the CLI binary, or set CODECHARTER_LICENSE to the path of the file.

Could not read '<path>'

A license file was found but could not be opened, typically because of missing file permissions. Make sure the user running the CLI has read access to the file.

License at '<path>' is not a valid JWS

The file was found but is not a valid JWS structure. Possible causes are an accidentally overwritten file, line-ending conversion by a version control system, or a file from a very old portal version. Re-download the license from the portal.

License at '<path>' is not signed by a key this CLI trusts

The token is syntactically correct but signed by a key this CLI does not recognize. Typically occurs when there is a mismatch between a license from an older portal generation and a newer CLI. Solution: pull the current CLI version from the portal.

License expired on <date>

The token's signature is fine but the expiry date from the subscription has passed. Renew the subscription in the portal and then re-download the archive. The expiry check tolerates five minutes of clock skew, so a slightly drifting system clock does not trigger this error.

License requires CLI >= <version> / License only covers CLI <= <version>

The license was issued with a version bracket that does not include this CLI. Solution: regenerate the license in the portal, or use a CLI version within the bracket.

Privacy

Validation runs completely offline. There is no phone-home; the CLI does not need network access to validate the license. The signature is sufficient.

The token contains: user ID (UUID), account email, plan name, issuance date, expiry date, the issuer name, a random license ID, and the optional CLI version bounds (min_ver/max_ver). These values are obvious to the license holder anyway; they are not a secret but the anchor of the license itself.