On CI runners, in Docker images, and on Linux or macOS developer machines, the standalone CLI build is the right approach. A self-contained archive (the CLI plus its bundled runtime), no separate runtime install needed.
Which build for which platform
| File | For |
|---|---|
codecharter-X.Y.Z-win-x64.zip |
Windows x64 |
codecharter-X.Y.Z-linux-x64.tar.gz |
Linux x64 (glibc-based) |
codecharter-X.Y.Z-osx-x64.tar.gz |
macOS Intel |
codecharter-X.Y.Z-osx-arm64.tar.gz |
macOS Apple Silicon |
All four are available in the portal at /downloads.
Install as a .NET global tool
If you already have the .NET 9 SDK, installing the CodeCharter.Cli package
from nuget.org is the quickest path on any platform:
dotnet tool install --global CodeCharter.Cli
codecharter --version
To update to the latest version:
dotnet tool update --global CodeCharter.Cli
The global tool still requires a valid CodeCharter license / API key at
runtime, exactly like the standalone archives below; installing the package
does not by itself grant a usage right. See
CLI licensing for how to configure
CODECHARTER_API_KEY or a codecharter.license file.
Download and unpack
# Example: Linux x64
curl -L -o codecharter.tar.gz \
-H "Authorization: Bearer $CODECHARTER_API_KEY" \
https://codecharter.tools/api/v1/cli/linux-x64/latest
mkdir -p /opt/codecharter
tar -xzf codecharter.tar.gz -C /opt/codecharter
chmod +x /opt/codecharter/codecharter
/opt/codecharter/codecharter --version
The archive contains only the CLI and its runtime; no rules are bundled. Rules
come from the profiles in your .codecharter/config.yml, resolved against the
portal (run codecharter restore to fetch them into the local cache).
The API key does double duty: besides authorizing the download, the CLI uses
the CODECHARTER_API_KEY environment variable at runtime to automatically
obtain a short-lived license from the portal. Without a valid license, every
command exits with code 6. See CLI licensing.
On macOS you may need to click through the Gatekeeper check on first launch (System Settings → Privacy & Security → "Open Anyway") or remove the quarantine attribute:
xattr -dr com.apple.quarantine /opt/codecharter
The binaries are currently not notarized. Use one of the workarounds above on macOS.
In Docker
Never bake the API key into an image layer. Using
ARGfor secrets writes the value into the build-layer history and makes it extractable from the image. Use a BuildKit secret mount instead (requires Docker 18.09+ withDOCKER_BUILDKIT=1or BuildKit enabled by default).
# syntax=docker/dockerfile:1
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /app
COPY . .
RUN dotnet build -c Release
FROM mcr.microsoft.com/dotnet/runtime:9.0
WORKDIR /app
RUN --mount=type=secret,id=cgkey \
mkdir -p /opt/codecharter \
&& curl -sSL \
-H "Authorization: Bearer $(cat /run/secrets/cgkey)" \
-o codecharter.tar.gz \
https://codecharter.tools/api/v1/cli/linux-x64/latest \
&& tar -xzf codecharter.tar.gz -C /opt/codecharter \
&& rm codecharter.tar.gz \
&& chmod +x /opt/codecharter/codecharter
ENV PATH="/opt/codecharter:${PATH}"
COPY --from=build /app/publish ./
Build with:
DOCKER_BUILDKIT=1 docker build --secret id=cgkey,src=<(echo "$CODECHARTER_API_KEY") -t myapp .
Alternatively, keep the codecharter binary out of the image entirely and run
the analysis on the CI runner before the Docker build. analyze expects the
path to a .sln, .slnx, or .csproj file:
codecharter analyze MySolution.sln --output sarif:codecharter.sarif
docker build -t myapp .
Caching in CI
The archives are self-contained and weigh in at a few tens of megabytes. If your CI provider supports caching, cache the unpacked directory rather than the archive. Unpacking is the more expensive operation compared to downloading.
The official GitHub Action does not use the standalone archives; it runs CodeCharter from a container image. See GitHub Actions.
Automatic updates
The CLI keeps itself current. On every run, right after the license check, it
starts a quick background check for a newer release and — if one is published —
fetches it. The update is out-of-band and next-run: the command you started
always finishes on its current version, and the newer version becomes active on
a later launch. Nothing ever blocks on the update, and a binary is never swapped
mid-run, so the long-lived mcp server is never disrupted mid-session.
The check is throttled to once every 24 hours (a small state file records when it last ran), so most runs do no network work at all.
How the update is applied depends on how the CLI was installed:
- .NET global tool (
dotnet tool install --global CodeCharter.Cli): the CLI runsdotnet tool update --global CodeCharter.Clifor you. - Standalone archive / Docker: the CLI downloads the matching archive from
the portal (using the same short-lived license the license check just renewed),
verifies its SHA-256, and atomically swaps it into the install directory once no
codecharterprocess is holding those files open. The previous version is kept as an.baksibling for rollback.
State and staged downloads live under your per-user config directory —
$XDG_CONFIG_HOME/codecharter, %APPDATA%\CodeCharter, or ~/.config/codecharter:
self-update.json (the throttle/state file) and staging/<version>/ (a verified
release waiting to be activated).
Opting out (CI)
For reproducible pipelines you generally pin a version and turn auto-update off. Either flag suppresses the check:
# Per run:
codecharter analyze MySolution.sln --skip-update
# Or for the whole pipeline, set the environment variable once:
export CODECHARTER_SKIP_UPDATE=1
CODECHARTER_UPDATE_INTERVAL overrides the throttle interval, in whole seconds
(0 forces a check on every run — useful for testing the update path):
export CODECHARTER_UPDATE_INTERVAL=3600 # check at most once an hour
Version pinning
Instead of /latest/ you can pin a specific version:
https://codecharter.tools/api/v1/cli/linux-x64/1.0.12
The version selector also accepts prefixes such as 1.0 or v1; the newest
matching release is served. Download responses carry an X-CodeCharter-Sha256
header that your pipeline can use to verify the integrity of the archive.
If your subscription has expired, the download endpoint returns HTTP 402.
We recommend pinning for reproducible builds. See Versioning.
PATH setup
If you do not have the CLI directory on the PATH, you can use the full path. For a persistent PATH setup on a workstation:
# Linux/macOS, in .bashrc or .zshrc
export PATH="/opt/codecharter:$PATH"
# Windows — reads and writes the persistent User PATH (survives reboots)
$current = [Environment]::GetEnvironmentVariable("PATH", "User")
[Environment]::SetEnvironmentVariable("PATH", "$current;C:\codecharter", "User")