# 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](https://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 with `cx repo unzip` (see [Troubleshooting](#troubleshooting)). - **Python 3.9 or newer** — only for the pip route. The two [`uv`](https://github.com/astral-sh/uv) routes 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. ```bash curl -fLo uv-install.sh https://astral.sh/uv/install.sh # Linux, macOS sh uv-install.sh . "$HOME/.local/bin/env" ``` ```bat 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. ```bash 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: ```bash 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: ```bash 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](#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: ```bash 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+: ```bash 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. ```bash 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: ```text 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 | |---|---| | `uv tool install "cmeta[server]"` (Option 1, and the website installer) | `uv tool upgrade cmeta` — keeps the extras it was installed with | | `uv tool install ... "cmeta[server] @ git+https://...@main"` | `uv tool install --force "cmeta[server] @ git+https://github.com/cTuningLabs/cmeta.git@main"` — the version number does not change between commits, so `--force` is what makes it reinstall | | `uv pip install cmeta` in a venv (Option 2) | `uv pip install -U cmeta`, with the venv activated | | `pip install cmeta` in a venv (Option 3) | `pip install -U cmeta`, with the venv activated (or `python -m pip install -U cmeta`) | | `uv pip` / `pip install ... @ git+https://...` | `uv pip install --force-reinstall "cmeta @ git+https://github.com/cTuningLabs/cmeta.git@main"` (or the same with `pip install`) | | an editable install (`pip install -e .`, `install.sh --editable`) | `git pull` in the checkout; reinstall only if the dependencies in `pyproject.toml` changed | | `install.sh` / `install.ps1` from a copied source tree | run it again: it installs with `--force`, so it upgrades in place | The website installer ([cTuning.ai/project/cmeta/cmeta.install](https://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: ```bash 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: ```bash 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://`) has no history to pull: remove it with `cx repo delete ` (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 | `CMETA_HOME` | used as-is | Explicit, and beats everything below. | | 2 | `$VIRTUAL_ENV` | + `/CMETA` | An activated virtual environment. | | 3 | `$CONDA_PREFIX` | + `/CMETA` | An activated conda environment. | | 4 | `CMETA_HOME2` | used as-is | A global default that a venv overrides. | | 5 | `~/CMETA` | — | 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= …` 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): ```text 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 `/CMETA`. Ask cMeta instead: `cx --print-home` for the home, `cx repo find ` 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: ```bash export CMETA_HOME="$HOME/CMETA" echo 'export CMETA_HOME="$HOME/CMETA"' >> ~/.bashrc ``` ```bat 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 install` already > creates native shims (`cx`, and `cx.exe` on Windows) and `uv tool update-shell` > puts them on `PATH`. Wrapping `uv run cx` in a shell script and pinning > `UV_PROJECT`/`PATH` to one project's `.venv` ties your global `cx` to that > project: its dependency changes alter your CLI, a broken lockfile there breaks > `cx` everywhere, 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 | |---------|-----------| | `pip install cmeta` | Serial use — the `cx` / `cmeta` CLI and the `CMeta` Python class. | | `pip install "cmeta[server]"` | The above **plus** FastAPI, uvicorn, jinja2, starlette and itsdangerous — needed to *host* an async app such as the shipped `cserver`. | | `pip install "cmeta[dev]"` | pytest, pytest-cov, flake8 for working on cMeta itself. | | `pip install "cmeta[all]"` | 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 ``, with file locks and atomic writes protecting the index and the artifact metadata. Details and examples in [async-and-concurrency.md](async-and-concurrency.md). --- ## Verify the installation ```bash cmeta --help cmeta --version ``` or using the short alias: ```bash cx --help cx --version ``` A first end-to-end check — list known repositories: ```bash 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](using-cmeta.md). --- ## Python interface cMeta can also be driven programmatically through the same uniform `access` interface used by the CLI: ```python 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: ```bash 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.: ```bat 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: ```bash cx run , [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`** — after `uv tool install`, run `uv tool update-shell` and open a new shell. Otherwise ensure your Python `Scripts`/`bin` directory is on `PATH`, or call the module directly with `python -m cmeta …`. - **`error: externally-managed-environment`** — PEP 668: most current Linux distributions refuse a `pip install` into the system interpreter. Use **Option 1** (`uv tool`, which never touches it), a virtual environment, or add `--break-system-packages` deliberately. - **`uv pip install` refuses 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](#choosing-where-repositories-live), and `cx --version` to see which one you are in. - **`python3 -m venv` fails on Debian/Ubuntu** — `python3-venv` is a separate package: `sudo apt-get install -y python3-venv`. - **Permission or cache errors on first run** — point `--meta.file_cache` at a writable location with enough free space (model/build caches can be large). - **Tool/version detection issues** — run with `-v` to see how cMeta is detecting compilers, Python and accelerators. - **`cx --version` still shows the old version after an update** — another `cx` comes first on `PATH`: typically a `pip install` into a system Python next to a `uv tool` install. `which -a cx` (Linux, macOS) or `where cx` (Windows) lists them all, and `cx --version` prints the one that runs (its `python path` and `package 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 ...` or `pip install --force-reinstall ...`, as [Updating cMeta](#updating-cmeta) shows. - **Windows: `An Application Control policy has blocked this file`** — as `ImportError: DLL load failed while importing unicodedata` from `cx`, git failing to load `libcurl-4.dll` / `libzstd.dll`, or `cxt.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; afterwards `cx`, `cxt` and 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 `--python` matters once uv has already downloaded its own interpreter, which it prefers over a system one) — and fetch repositories without git, with the `curl.exe` that ships with Windows: ```bat 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.exe` in `%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`. A `cx.cmd` on `PATH` holding `@"%APPDATA%\uv\tools\cmeta\Scripts\python.exe" -m cmeta %*` gives `cx` back; `cxt ...` is `cx task run ...`. --- Next steps: - Everyday usage (repos, plugins, artifacts, reindex) — [using-cmeta.md](using-cmeta.md) - Why cMeta exists and its design principles — [motivation.md](motivation.md) - Async use (FastAPI) and concurrency guards — [async-and-concurrency.md](async-and-concurrency.md) - Working with `config` artifacts — [configuration.md](configuration.md) - Connecting to the cTuning.ai platform — [cplatform.md](cplatform.md) - All guides — [documentation index](README.md)