Installing cMeta
cMeta (CLI: cx / cmeta) is a small, portable Python package with minimal
dependencies. It runs on Linux, macOS and Windows and supports Python 3.9+.
There is also an interactive installer that assembles these commands for your OS, shell and package manager: cTuning.ai/project/cmeta/cmeta.install
Requirements
Git —
cx repo get --url=...clones content repositories over git, and so does the install-from-source route. Where git is missing or blocked, a repository can also be fetched as an archive and registered withcx repo unzip(see Troubleshooting).Python 3.9 or newer — only for the pip route. The two
uvroutes below let uv fetch its own interpreter, so they work on a host with no usable Python and no root.
Installing uv
astral’s own installer is used on every platform in preference to whatever the
distribution packages — one command shape everywhere, and no dependency on a
distro keeping up with uv releases. It is downloaded first and then run, so it
can be read before it runs; on Windows the piped irm ... | iex form is what
Microsoft Defender flags as a download-and-run trojan. The last line puts uv on
PATH in the current shell, since the installer arranges it only for new ones.
curl -fLo uv-install.sh https://astral.sh/uv/install.sh # Linux, macOS
sh uv-install.sh
. "$HOME/.local/bin/env"
curl.exe -fLo uv-install.ps1 https://astral.sh/uv/install.ps1
powershell -ExecutionPolicy ByPass -File uv-install.ps1
set "PATH=%USERPROFILE%\.local\bin;%PATH%"
On a minimal Linux image install curl first (apt-get install -y curl,
dnf install -y curl, …).
Option 1 — uv tool (a global cx, recommended)
Installs cMeta as a standalone command, the way uv or ripgrep are installed:
its own private environment that you never activate, real cx / cmeta /
cxt / cserver shims on PATH, and an interpreter uv downloads itself.
uv tool install "cmeta[server]"
uv tool update-shell # put the shims on PATH (once per machine)
cx --version
The server extra is included because cx app run cserver cannot start
without it — there is no uvicorn to run it with, and a uv tool
environment has no pip to add one afterwards. Drop it (uv tool install cmeta)
if you will never run the web app.
Which Python. uv uses a Python that is already on the machine; on a machine without one it downloads its newest. That is 3.15 today, and not every dependency of cMeta ships wheels for 3.15 yet (PyYAML does not), so the install would have to compile it and fails without a C compiler. Until they all do, ask for an earlier one on such a machine — the website installer does so by default:
uv tool install --python ">=3.9,<3.15" "cmeta[server]"
Quote the extra. In zsh — the default shell on macOS — square
brackets are a filename pattern, so an unquoted cmeta[server] never reaches
uv: it fails with zsh: no matches found. "cmeta[server]" works in every
shell.
Installing from a branch rather than a release, to try something before it ships:
uv tool install --force "cmeta[server] @ git+https://github.com/ctuninglabs/cmeta@dev"
Pick this when cMeta is a tool you use everywhere rather than a dependency
of one project — which is how it is normally used. It also sidesteps PEP 668
entirely, since it never touches the system interpreter, and
uv tool upgrade cmeta upgrades the CLI in isolation.
Nothing else to set up. Repositories, the index and the caches go to
~/CMETA (%USERPROFILE%\CMETA on Windows). Set CMETA_HOME only to keep them
somewhere else, or to keep that one folder even while a project’s virtual
environment is active; see
Choosing where repositories live.
Option 2 — uv + a project virtual environment
For when cMeta is a dependency of one project, and its repositories should live and die with that project:
uv venv cmeta-env # no Python on the machine: uv venv --python ">=3.9,<3.15" cmeta-env (see Option 1)
source cmeta-env/bin/activate # Windows: cmeta-env\Scripts\activate.bat
uv pip install cmeta
cx --version
Option 3 — pip + a project virtual environment
Using only what ships with Python 3.9+:
python3 -m venv cmeta-env
source cmeta-env/bin/activate # Windows: cmeta-env\Scripts\activate.bat
pip install cmeta
cx --version
Latest from source
Add --force (uv tool) or --force-reinstall (uv / pip): the version number
does not change between commits on main, so the installer would otherwise
decide there is nothing to do.
uv tool install --force "cmeta @ git+https://github.com/cTuningLabs/cmeta.git@main"
uv pip install --force-reinstall "cmeta @ git+https://github.com/cTuningLabs/cmeta.git@main"
pip install --force-reinstall "cmeta @ git+https://github.com/cTuningLabs/cmeta.git@main"
Extras combine with the direct reference as usual:
"cmeta[server] @ git+https://...".
Updating cMeta
Start with cx --version. It says how this cMeta was installed, prints the
command that updates it, and warns when a newer release is out:
Installed as: uv tool, from PyPI
Update with: uv tool upgrade cmeta
The update command depends on how cMeta was installed, not on the OS:
Installed with |
Update with |
|---|---|
|
|
|
|
|
|
|
|
|
|
an editable install ( |
|
|
run it again: it installs with |
The website installer (cTuning.ai/project/cmeta/cmeta.install) has an Update mode that turns the same choices (OS, route, version, repositories) into these commands.
A specific version, to pin or to go back:
uv tool install --force "cmeta[server]==0.37.0"
pip install "cmeta==0.37.0"
Moving an install from git to PyPI (or back) is a reinstall from the other
source: uv tool install --force "cmeta[server]".
Updating the repositories you use
A content repository is updated by cMeta itself, not by pip or uv. One fetched
with cx repo get (a git clone) is updated with a pull, which also refreshes the
index:
cx repo list # what is plugged in
cx repo pull # every repository fetched with git: git pull + reindex each (asks first; -q does not ask)
cx repo pull cmeta-aops # one, by the name it was fetched with or by its alias (ctuninglabs@cmeta-aops)
A repository fetched as a zip (cx repo get cmeta://<name>) has no history to
pull: remove it with cx repo delete <alias> (this deletes the local copy,
including any local changes) and get it again — or get the git clone instead.
After a git pull done by hand inside a repository, run cx --reindex.
Choosing where repositories live
One directory — the cMeta home — holds repos.json, the plugged
repositories under repos/, the fast lookup index under index/, and the task
caches. By default it is ~/CMETA (%USERPROFILE%\CMETA on Windows), created
on first use, so there is nothing to configure. cMeta looks for it every time it
starts, in this order:
Source |
Becomes |
When |
|
|---|---|---|---|
1 |
|
used as-is |
Explicit, and beats everything below. |
2 |
|
+ |
An activated virtual environment. |
3 |
|
+ |
An activated conda environment. |
4 |
|
used as-is |
A global default that a venv overrides. |
5 |
|
— |
The fallback when nothing above is set. |
cx --version prints the home it resolved and, on the next line, what chose it
(cMeta home chosen by: …), and cx --home=<path> … overrides it for a single
command. cx --print-home prints the path alone, for scripts: one line, no
network access, and a home that does not exist yet is not set up.
The command that sets up a new home says so once, in one line of information on the standard output (the standard error is for errors only):
cMeta info: a new cMeta home is set up in /opt/venv/CMETA (chosen by VIRTUAL_ENV=/opt/venv - a virtual environment keeps a home of its own); set CMETA_HOME to keep the home elsewhere, "cx --version" shows the home in use
A script never assumes ~/CMETA. Inside a virtual or conda environment - a
container image that exports VIRTUAL_ENV is enough - the home is
<environment>/CMETA. Ask cMeta instead: cx --print-home for the home, cx repo find <alias> for the folder of a repository.
Set CMETA_HOME only to choose another folder, or to keep one home even
while a project’s virtual environment is active. Rule 2 reads an environment
variable, not the location of the cx you invoked. So a uv tool-installed
cx, run from a shell with a project venv activated, puts its repositories in
$VIRTUAL_ENV/CMETA. To have one home everywhere, or a home in another place,
set it once:
export CMETA_HOME="$HOME/CMETA"
echo 'export CMETA_HOME="$HOME/CMETA"' >> ~/.bashrc
setx CMETA_HOME "%USERPROFILE%\CMETA"
Use CMETA_HOME2 instead when you want a shared default that an activated
virtual environment is still allowed to override.
A hand-written wrapper script is not needed.
uv tool installalready creates native shims (cx, andcx.exeon Windows) anduv tool update-shellputs them onPATH. Wrappinguv run cxin a shell script and pinningUV_PROJECT/PATHto one project’s.venvties your globalcxto that project: its dependency changes alter your CLI, a broken lockfile there breakscxeverywhere, and every invocation pays a project re-resolve.
Serial or async — choosing extras
cMeta can be driven serially (a script, the CLI, a CI step) or asynchronously from an event loop inside FastAPI or another asyncio server. Both modes use the same categories, artifacts and commands.
Install |
Gives you |
|---|---|
|
Serial use — the |
|
The above plus FastAPI, uvicorn, jinja2, starlette and itsdangerous — needed to host an async app such as the shipped |
|
pytest, pytest-cov, flake8 for working on cMeta itself. |
|
dev + async + server. |
The async class CMetaAsync needs no extra — it is built on asyncio and
concurrent.futures from the standard library, so the base install is enough
to await cm.access(...). The [server] extra is only about the web stack you
run it in. (There is also an [async] extra; it is intentionally empty and
exists so cmeta[server] can reference it.)
cMeta is designed for concurrent use: several processes may share one
<CMETA_HOME>, with file locks and atomic writes protecting the index and the
artifact metadata. Details and examples in
async-and-concurrency.md.
Verify the installation
cmeta --help
cmeta --version
or using the short alias:
cx --help
cx --version
A first end-to-end check — list known repositories:
cx repo list
Next, walk through everyday usage — pulling in more content repositories, adding your own categories (plugins) and artifacts, and keeping the local index healthy — in using-cmeta.md.
Python interface
cMeta can also be driven programmatically through the same uniform access
interface used by the CLI:
from cmeta import CMeta
cm = CMeta()
r = cm.access({'category': 'repo', 'command': 'list'})
print(r)
Optional configuration
cMeta works out of the box, but a few settings are commonly useful — for example redirecting the large-file/build cache to a dedicated drive, enabling version checks for detected tools, and choosing a default Git transport:
cx config set task --meta.file_cache=/path/to/large/cache
cx config set task --meta.check_versions
cx config set default --meta.default_git=git@github.com:
On Windows the cache path is typically a separate drive, e.g.:
cx config set task --meta.file_cache=x:\cmeta-file-cache-windows
Working with artifact repositories
cMeta executes artifacts (programs, models, datasets, tasks) that live in content repositories. Once you have access to such a repository, you run an artifact with:
cx <category> run <alias>,<uid> [flags]
Common flags include -v (verbose), --clean and `-q’ (quiet)
Common flags for category program include
--compute=cpu|cuda|rocm|metal|xpu to select a compute backend.
--clean to clean cache
Troubleshooting
cx: command not found— afteruv tool install, runuv tool update-shelland open a new shell. Otherwise ensure your PythonScripts/bindirectory is onPATH, or call the module directly withpython -m cmeta ….error: externally-managed-environment— PEP 668: most current Linux distributions refuse apip installinto the system interpreter. Use Option 1 (uv tool, which never touches it), a virtual environment, or add--break-system-packagesdeliberately.uv pip installrefuses to run — uv will not install into an interpreter outside a virtual environment unless told to. Activate one, or add--system.Repositories keep disappearing between shells — the home moved with you. A venv activated in one terminal and not in another resolves to two different homes; see Choosing where repositories live, and
cx --versionto see which one you are in.python3 -m venvfails on Debian/Ubuntu —python3-venvis a separate package:sudo apt-get install -y python3-venv.Permission or cache errors on first run — point
--meta.file_cacheat a writable location with enough free space (model/build caches can be large).Tool/version detection issues — run with
-vto see how cMeta is detecting compilers, Python and accelerators.cx --versionstill shows the old version after an update — anothercxcomes first onPATH: typically apip installinto a system Python next to auv toolinstall.which -a cx(Linux, macOS) orwhere cx(Windows) lists them all, andcx --versionprints the one that runs (itspython pathandpackage path). Update that one, or uninstall the one you do not use (uv tool uninstall cmeta,pip uninstall cmeta).An update seems to do nothing — an install from git keeps the same version number between commits, so a plain upgrade decides there is nothing to do: use
uv tool install --force ...orpip install --force-reinstall ..., as Updating cMeta shows.Windows:
An Application Control policy has blocked this file— asImportError: DLL load failed while importing unicodedatafromcx, git failing to loadlibcurl-4.dll/libzstd.dll, orcxt.exe“blocked by your organization’s Device Guard policy”. Smart App Control, on by default on new Windows 11 PCs, refuses every binary that is neither signed nor known to Microsoft: the interpreter uv downloads, uv’s command shims, the DLLs of Git for Windows (Microsoft’s own git release ships the same unsigned DLLs), and every program you compile. The fix is to turn it off: Settings > Privacy & security > Windows Security > App & browser control > Smart App Control settings > Off. The switch is one-way, and it is the normal state of a development machine; afterwardscx,cxtand git work as installed, nothing to reinstall. To keep it on instead, stay with signed components only: install Python from the Microsoft Store and put cMeta on that interpreter —uv tool install "cmeta[server]" --python python.exe(the--pythonmatters once uv has already downloaded its own interpreter, which it prefers over a system one) — and fetch repositories without git, with thecurl.exethat ships with Windows:curl.exe -fLo cmeta-aops.zip https://github.com/ctuninglabs/cmeta-aops/archive/refs/heads/main.zip cx repo unzip cmeta-aops.zip
The same two commands update the repository later. uv’s command shims (
cx.exe,cxt.exein%USERPROFILE%\.local\bin) are unsigned launchers and can be blocked as well (blocked by your organization's Device Guard policy). The signed way in is the interpreter of the tool environment itself, a copy of the Store Python’s launcher:"%APPDATA%\uv\tools\cmeta\Scripts\python.exe" -m cmeta --version. Acx.cmdonPATHholding@"%APPDATA%\uv\tools\cmeta\Scripts\python.exe" -m cmeta %*givescxback;cxt <task> ...iscx task run <task> ....
Next steps:
Everyday usage (repos, plugins, artifacts, reindex) — using-cmeta.md
Why cMeta exists and its design principles — motivation.md
Async use (FastAPI) and concurrency guards — async-and-concurrency.md
Working with
configartifacts — configuration.mdConnecting to the cTuning.ai platform — cplatform.md
All guides — documentation index