Public copy of this guide (no login): https://dist.cortexbuild.dev/guides/onboarding.html — always the latest published version. Release notes: https://dist.cortexbuild.dev/guides/releases.html
The complete, copy-pasteable setup for a customer who has a license token, on any operating system. Five minutes end to end.
Your CortexBuild contact will give you three values:
Value Placeholder below Example License token <LICENSE_TOKEN>cblk_…License service URL <LICENSE_URL>https://license.cortexbuild.devPackage index URL https://dist.cortexbuild.dev/index.htmlhttps://dist.cortexbuild.dev/index.html
On the CortexBuild-managed plan you can use the hosted endpoints directly and only need your own token:
| Value | Current endpoint |
|---|---|
<LICENSE_URL> |
https://license.cortexbuild.dev |
https://dist.cortexbuild.dev/index.html |
https://dist.cortexbuild.dev/index.html |
These are canonical custom domains, not raw infrastructure hostnames, so they survive a region or provider move. Use them exactly as written.
requires-python = ">=3.11"). macOS ships 3.9, so
most Mac users install a newer one first. A .NET-only dev machine
typically has no Python at all — that's expected, not a problem; install
one with the guide below before step 2.<LICENSE_URL>.Check whether Python is on PATH at all, and which version:
python3 --version # macOS / Linux
py --version # Windows
If either command prints command not found (macOS/Linux) or 'py' is not
recognized (Windows), Python is not installed — not just old. If it prints a
version below 3.11, install a newer one alongside it, same as below.
brew install python@3.12'py' is not recognized. (winget install Python.Python.3.12 sets PATH the
same way, no checkbox needed.)python3.12 package (e.g. apt install python3.12 python3.12-venv)Re-run py --version (Windows) or python3 --version (macOS/Linux) afterwards
to confirm it now resolves to 3.11+.
Locked-down machine, can't add to PATH? CortexBuild only needs an
interpreter to exist — it does not have to be on PATH. Install Python anyway
(the checkbox unticked is fine), note the absolute path the installer used
(Windows default: %LocalAppData%\Programs\Python\Python312\python.exe), and
use that absolute path everywhere this guide says python3 / py / python.
Use a virtual environment so CortexBuild is isolated from your projects, and put
it outside any repository — it is a tool you run against repos, not a
dependency of one, and a venv inside a checkout lands in git status.
macOS / Linux
python3.12 -m venv "$HOME/.venvs/cortexbuild"
"$HOME/.venvs/cortexbuild/bin/pip" install --upgrade cortexbuild-core --find-links https://dist.cortexbuild.dev/index.html
Windows (PowerShell)
py -3.12 -m venv "$env:USERPROFILE\.venvs\cortexbuild"
& "$env:USERPROFILE\.venvs\cortexbuild\Scripts\pip.exe" install --upgrade cortexbuild-core --find-links https://dist.cortexbuild.dev/index.html
It is not on PyPI — the --find-links flag is required. cryptography is a
base dependency (it verifies your signed license offline), so there is no
extra to add; a bare install is complete. Repo analysis is optional:
cortexbuild-core[graph].
[signing]is no longer needed — it is retained only as an empty alias so old commands keep resolving.cortexbuild-core[signing]still works; it adds nothing.
This is the difference between "it worked when I set it up" and "my AI tool can't find it the next day". It bites after setup appears to have worked, so it is worth understanding, not just pasting.
Why activating the venv is not enough. source .../activate and inline
export PATH=… last only for the shell that ran them. A new session is a new
shell, and your AI assistant starts one per session, sometimes per command —
so whatever made cortexbuild findable last time is gone.
Why the usual PATH files don't help either. Your assistant runs commands in
a non-interactive shell (zsh -c "…", bash -c "…"), and sometimes launches
the binary directly from a GUI app with no shell at all. The interactive
startup files are not read in those cases:
| Shell / launch | Reads | Does not read |
|---|---|---|
zsh -c (non-interactive) |
~/.zshenv |
~/.zshrc, ~/.zprofile |
bash -c (non-interactive) |
the file named by $BASH_ENV |
~/.bashrc, ~/.bash_profile |
| GUI-launched IDE (macOS) | the system PATH (/etc/paths, launchd) |
any shell rc file |
So a PATH line in ~/.zshrc or ~/.bash_profile works when you type
cortexbuild and fails for your assistant with command not found — the exact
"works for me" trap. When it fails, governance still applies (your agent warns
and continues), but nothing is recorded and the gap is invisible to your
administrator.
Two ways to fix it. Option A is the robust one — it works for every shell and for GUI-launched tools, because it puts the command where every process already looks.
macOS / Linux. Find a directory that is already on the non-interactive PATH, then symlink the command into it:
# 1. See what a NON-INTERACTIVE shell already has on PATH:
zsh -c 'echo $PATH' | tr ':' '\n' # or: bash -c 'echo $PATH' | tr ':' '\n'
# 2. Symlink into a writable directory from that list. /usr/local/bin is on the
# default macOS/Linux PATH; on Apple-Silicon Homebrew it is often /opt/homebrew/bin.
ln -sf "$HOME/.venvs/cortexbuild/bin/cortexbuild" /usr/local/bin/cortexbuild
# (prefix with sudo if the directory is not writable)
The symlink points at the venv's launcher, so upgrading the venv needs no repointing.
Windows. Add the venv's Scripts directory to your User PATH — a real
environment variable that every new process inherits, GUI or shell:
$venv = "$env:USERPROFILE\.venvs\cortexbuild\Scripts"
$cur = [Environment]::GetEnvironmentVariable("PATH","User")
if ($cur -notlike "*$venv*") {
[Environment]::SetEnvironmentVariable("PATH", "$venv;$cur", "User")
}
Restart the IDE afterwards so it picks up the new environment.
If cortexbuild itself refuses to start. The cortexbuild command is a
small launcher the installer wrote. If you see uv trampoline failed to
canonicalize script path (a uv-made launcher on Windows that cannot resolve
its own path — typical for a venv created inside the checkout or on a mapped
drive), the CLI is fine and the launcher is not. Two fixes, in order of
preference:
py -3.12 -m venv and pip (steps above) — and delete the repo-local one.powershell
& "<venv>\Scripts\python.exe" -m cortexbuild_core telemetry doctor
If it fails only inside your AI assistant's terminal. Some assistants run
commands in a sandbox (Antigravity does) that cannot load DLLs from the
checkout — ImportError: DLL load failed while importing _pydantic_core:
Access is denied — and has no py/python on its PATH. That is the
sandbox, not CortexBuild, and no bypass inside the sandbox will work. Do the
venv setup above in your own terminal (the user-profile venv on the User
PATH is normally reachable from the sandbox), then run
cortexbuild telemetry doctor once from the assistant's terminal. If that
still says Access is denied, allow-list the venv path (or turn off the
terminal sandbox for the workspace) in the assistant's settings.
If the assistant's terminal instead says 'cortexbuild' is not recognized after you set PATH: fully quit and relaunch the assistant (a running process never sees a PATH edit), and prefer the absolute path from inside an assistant anyway — sandboxed terminals inject their own environment and do not reliably inherit the machine PATH:
& "$env:USERPROFILE\.venvs\cortexbuild\Scripts\cortexbuild.exe" telemetry doctor
For VS Code-derived assistants, settings.json →
"terminal.integrated.env.windows": { "PATH": "C:\\Users\\<you>\\.venvs\\cortexbuild\\Scripts;${env:PATH}" }
makes the PATH explicit for every terminal the assistant opens. Your own
commands record either way; only agent-attributed dimensions are affected
until the assistant can run the CLI.
Use this if you cannot write to a system directory. It fixes … -c shells but
not a GUI-launched IDE.
# zsh — .zshenv, NOT .zshrc. This is the one startup file a non-interactive
# `zsh -c` reads, so it is the only shell file that reaches your AI tool.
echo 'export PATH="$HOME/.venvs/cortexbuild/bin:$PATH"' >> ~/.zshenv
bash users: use Option A. There is no clean shell-file equivalent for a non-interactive
bash -c— it reads only$BASH_ENV, and$BASH_ENVhas to already be set in the environment your tool launches from (a login profile or the OS environment), which is the very problem Option A sidesteps. Putting a PATH line in.bashrcor.bash_profilewill not reachbash -c. Symlink the command (Option A) instead.
Checking your own terminal proves nothing — that shell was never the broken one. Test the non-interactive one:
zsh -c 'cortexbuild version' # macOS / Linux
cmd /c "cortexbuild version" # Windows — a fresh no-profile process
A version number here means every future session will find it too.
Bind this machine and cache a signed lease. Activation is written to disk
(.cortexbuild/license/), so it persists across sessions — unlike PATH,
which is why a machine can show "activated" while the command is "not found".
cortexbuild auth activate --key <LICENSE_TOKEN> --url <LICENSE_URL>
cortexbuild auth status --json
auth status should show "ok": true, "trusted": true, "signed": true, and
your plan. Activation consumes one device seat; repeat on each machine up to
your cap. If this machine was activated before, this is a harmless no-op.
From the root of the repo you want to govern:
cortexbuild init run .
This writes a .cortexbuild/ folder (rules, agents, recurrence ledger,
onboarding summary). Open .cortexbuild/ONBOARDING.md for guided next steps.
cortexbuild render
This generates the always-on instruction files your existing AI tools read —
CLAUDE.md, AGENTS.md, GEMINI.md, .github/copilot-instructions.md,
.cursor/rules/* — then commit them. From now on the AI tools you already use
operate under CortexBuild governance.
cortexbuild doctor # instruction surfaces are wired
cortexbuild verify # OWASP Agentic Top-10 self-assessment
cortexbuild auth status # license
Every command records to a local ledger whether or not a collector is
declared. Recording is not reporting: until the collector is declared in
.cortexbuild/telemetry.yaml, nothing leaves the machine and the org's
portal shows no activity for you — a repo in that state prints a !
warning naming the remedy (recorded locally only — run cortexbuild
telemetry configure), never a bare OK.
cortexbuild adopt, cortexbuild onboard, and cortexbuild init write this
file for you automatically (0.2.50 for adopt/onboard; init joined in 0.2.52)
the moment your licence verifies here — no extra step, and it never silently
overwrites a config you already committed. git status after any of the three
should show .cortexbuild/telemetry.yaml as untracked/new; commit it (it
holds no secrets):
git add .cortexbuild/telemetry.yaml
git commit -m "chore: declare the CortexBuild collector"
Skipped adopt/onboard, self-hosting a collector, or reporting under a
different --project-id? Declare it explicitly instead:
cortexbuild telemetry configure --org-id <your-org-id> --project-id <estate-or-team-name>
git add .cortexbuild/telemetry.yaml
git commit -m "chore: declare the CortexBuild collector"
--org-id is the organisation id from your licence (cortexbuild auth status
prints it); --project-id is the estate or team the repo reports under, which
is how the portal groups repositories.
Do not pass --service-url. The collector URL defaults to the canonical
https://license.cortexbuild.dev, and that is the only address to declare. A
cloud-infrastructure hostname (anything ending azurecontainerapps.io,
azurewebsites.net, amazonaws.com and the like) answers today and stops
answering the day the service moves — if an assistant fills one in for you,
re-run the command above without it.
Then confirm telemetry actually reaches the collector, not just the local disk — this ends with a real push and says whether it landed:
cortexbuild telemetry doctor
Run it in a terminal and read the CLI's own lines. OK collector configured:
<url> and OK event reaches the collector are the two that matter; a
LOCAL-ONLY / no collector line means step 8 was skipped.
Recorded a few commands before this step? Nothing is lost. Every event
written to the local ledger with no collector configured stays there; the
moment a collector is declared, cortexbuild telemetry flush --ledger (or
just a plain cortexbuild telemetry flush — it runs the ledger drain
automatically the first time it finds one) pushes that backlog, oldest first.
cortexbuild telemetry show names the count if there is one.
Are token counts automatic, or do I have to pass --tokens myself?
On Claude Code, automatic: the rendered Stop hook meters the turn from the
transcript (subagents included) and records the response event itself, so
cortexbuild telemetry record defers to it (deferred_to: "stop-hook" in
--json) instead of writing a second event. On every other host,
cortexbuild telemetry record never guesses a token count on its own —
--tokens (or --exact-tokens for a metered figure) is passed only when a
meter or your host itself reported the count to you; never invent one.
cortexbuild telemetry show and cortexbuild telemetry doctor both name it
when response events carry no count so it does not go unnoticed, and a repo
can require a metered source with require_tokens: true in
.cortexbuild/telemetry.yaml (CI-friendly: record then exits 2 on a
meterable host with no active meter, instead of just warning — an
unmeterable host is never refused, since there is nothing to install there).
The signed lease renews automatically online. To renew explicitly (CI, or before
a long offline stretch): cortexbuild auth refresh. To free this machine's seat
(decommissioning a laptop): cortexbuild auth deactivate.
Install into the job as in step 2, activate once (or set the token via the
environment), and confirm with cortexbuild auth status --json. The PATH
concern from step 3 applies here too: put the venv's bin/Scripts on the
job's PATH explicitly rather than relying on an interactive profile.
If this repo also carries an analysis/<system>/ or legacy/<system>/ layout
— the shape Anthropic's code-modernization plugin writes — see
Modernizing with CortexBuild
(public copy: https://dist.cortexbuild.dev/guides/modernization.html) for
how the setup above extends to govern that plugin's run: the same license and
telemetry you just configured, plus a frozen-baseline guard, an approval
record, and per-stage telemetry the plugin does not emit on its own.
| Symptom | Fix |
|---|---|
command not found: cortexbuild in your AI tool, but it works in your terminal |
Step 3 — the PATH is in an interactive-only file. Use Option A, then verify with zsh -c 'cortexbuild version'. |
| Worked yesterday, not found today in a new session | Same cause: the previous setup only affected that one shell. Step 3, Option A, makes it durable. |
license required on a command |
Run cortexbuild auth activate … (step 4), or auth status to see why. |
device seat limit exceeded |
You've hit your device cap. cortexbuild auth deactivate on an old machine, or ask your admin to reassign. |
A licence that will not verify (trusted: false) |
Plain reinstall (cryptography is a base dep): pip install --upgrade --force-reinstall cortexbuild-core --find-links https://dist.cortexbuild.dev/index.html, then cortexbuild auth status --json. Adding [signing] does nothing — it is an empty alias. |
| Activation network error | Confirm access to <LICENSE_URL>; corporate proxies may need allow-listing. |
Questions? Contact your CortexBuild administrator — they manage licenses, device seats, and plan entitlements from the admin portal.