Install qq

Put qq and qqsync on your machine in three copy-paste commands (four on a Mac), check them, and know what to do on a Mac.

You install two tools, both from source on GitHub, into one folder in your home directory: qq, the command line, and qqsync, the tool that reads a repo's infra/repo.toml. Nothing needs root. Outside ~/qq-tools, the only changes are one line that puts it on your PATH (on a Mac, or when qq-setup picks a newer python3.N, also one line that sets QQ_PYTHON), qq's own cache in ~/.cache/qq, and pip's download cache.

The three commands below, run on a fresh Linux account with an earlier qqsync pin. The last step opens a new shell and checks both versions.

Before you start

qq runs on Linux and macOS. You need git and Python 3.11.4 or newer with its venv module (on Debian or Ubuntu, the python3-venv package). That is all qq itself needs. qq uses python3 unless you set QQ_PYTHON to another Python, and the commands below do the same. The toolchains a repo builds with (Python 3.14.8, Node 24 with pnpm) are fetched later by qq sync, on Linux x86_64.

On a Mac, set up Python first. The python3 that comes with macOS is 3.9, too old for qq. brew install python@3.13 adds python3.13 but leaves python3 as it was, so tell qq to use it, then open a new terminal:

brew install python@3.13 && { grep -qs 'QQ_PYTHON=' ~/.zshrc || echo 'export QQ_PYTHON=python3.13' >> ~/.zshrc; }

If your shell is bash, add that export line instead to the first of ~/.bash_profile, ~/.bash_login or ~/.profile that you already have (~/.bash_profile if you have none). Bash reads only that one, and step 3 uses the same file.

Each command below runs inside ( … ), so it leaves your shell as it was, and each is safe to run again. To have them run for you instead, see Let qq-setup install it for you.

1. Install qq

qq is a git checkout, like depot_tools. This clones it and prints its version.

( set -e; mkdir -p ~/qq-tools; rm -rf ~/qq-tools/depot; git clone -q https://github.com/quirq-ai/qq ~/qq-tools/depot; ~/qq-tools/depot/bin/qq --version )

It prints qq 0.1.0. The first run also prints a line saying it set up its launcher under ~/.cache/qq.

2. Install qqsync

qqsync is the only program allowed to read or edit infra/repo.toml. It goes in its own Python environment, made with the same Python as qq and pinned to the same sync commit that qq pins, so the two always agree.

( set -e; mkdir -p ~/qq-tools; rm -rf ~/qq-tools/qqsync; "${QQ_PYTHON:-python3}" -m venv ~/qq-tools/qqsync; ~/qq-tools/qqsync/bin/pip install -q --disable-pip-version-check "qqsync @ git+https://github.com/quirq-ai/sync@9821f745690d5150cac70cd2eee54c97d431e6c3"; ~/qq-tools/qqsync/bin/qqsync --version )

It prints qqsync 0.1.0.

3. Put both on your PATH

This links both into ~/qq-tools/bin and adds that folder to your PATH: in ~/.bashrc for bash, in ~/.zshrc otherwise, and on a Mac in the first of ~/.bash_profile, ~/.bash_login or ~/.profile that bash already reads.

( case "$SHELL:$(uname)" in */bash:Darwin) for rc in ~/.bash_profile ~/.bash_login ~/.profile ~/.bash_profile; do [ -f "$rc" ] && break; done ;; */bash:*) rc=~/.bashrc ;; *) rc=~/.zshrc ;; esac; mkdir -p ~/qq-tools/bin && ln -sf ~/qq-tools/depot/bin/qq ~/qq-tools/qqsync/bin/qqsync ~/qq-tools/bin/ && { grep -qs 'qq-tools/bin:' "$rc" || printf '\nexport PATH="$HOME/qq-tools/bin:$PATH"\n' >> "$rc"; } && echo "qq-tools/bin is on PATH in $rc; open a new terminal" )

Open a new terminal and check:

qq --version && qqsync --version

You should see qq 0.1.0 and qqsync 0.1.0. Next: your first build.

How qq stays up to date

You rarely update qq by hand. Each repo pins the qq version it runs in its infra/repo.toml, and inside that repo qq runs exactly that version, installing it under ~/.cache/qq the first time. When the pin moves, the next qq you run picks up the new version.

Today: qq has no release tag yet, so a repo's 0.1.0 pin runs your own checkout in ~/qq-tools/depot. To update it, run step 1 again.

Auto-update

qq-setup can keep qq and qqsync up to date for you. It is off until you turn it on: tick the Auto-update box on This machine, or in a terminal add install --auto-update to the end of its command (--no-auto-update turns it off). It then writes ~/qq-tools/auto-update, naming the commits it installed.

  • At most once a day, in the background, qq reads the commits qq-setup has reviewed (pins.json on its main), so no command waits on the network.
  • When they are newer, the next qq first moves ~/qq-tools/depot to them, reinstalls qqsync if it is still the one qq-setup installed, then runs your command.
  • A checkout with changes of yours or at another commit, and a qqsync you installed another way, are left alone. Nothing runs when CI or QQ_PINNED is set.
  • What it did is in ~/qq-tools/auto-update.log. Inside a repo, the repo's pin still decides which qq runs.

On a Mac

qq and qqsync install the same way, once QQ_PYTHON points at a new enough Python (Before you start). What differs is the toolchains, which are published for Linux x86_64 only:

  • qq sync stops with no pin for platform macos-arm64. qq fetch clones the repo, then stops at the same point; carry on in the clone.
  • Install the pinned version yourself (Python 3.14.8, or Node 24 with pnpm) and pass it in: qq test --toolchain python=ROOT, where ROOT is the folder that holds its bin.
  • qq run uses the tools on your PATH and names the pinned toolchains it could not use.

Let qq-setup install it for you

qq-setup can run steps 1 to 3 for you, and later update or remove qq. It runs straight from GitHub with npx. Replace <commit> with the full id of the latest commit on main, so the link serves exactly that commit:

npx --allow-remote=root https://codeload.github.com/quirq-ai/setup/tar.gz/<commit>

It needs Node 22 or newer, and installs qq on Linux and macOS. On Windows it installs only xo, and for qq suggests WSL with Node 22 or newer installed inside it (qq-setup is not tested in WSL).

It checks your tools and opens a page in your browser, on step 1, This machine (it says "Start here" when qq is missing). It shows what is already here: qq and qqsync in ~/qq-tools, and whether they are on your PATH. Each tool starts at Keep (or Don't install), so nothing changes until you choose. For qq, pick Install if it is missing, or Update, Add to PATH or Remove if it is there; for xo, the same, or leave it. The page shows the exact commands, and Run runs them one at a time, with their output on the page, stopping at the first that fails. Press Done: close qq-setup when you are finished, then open a new terminal.

To install or update, it runs steps 1 to 3 of this page. On a Mac with no new enough Python, it first runs brew install python@3.13 and writes export QQ_PYTHON=python3.13 to the same file as the PATH line, so your shell finds it, bash or zsh. Otherwise, if python3 is too old but a newer python3.N is installed, it writes a QQ_PYTHON line for that one.

  • Update runs steps 1 to 3 again, which re-clones ~/qq-tools/depot. If that checkout has work of yours in it, the page warns you first; pick Keep to leave it.
  • Remove deletes ~/qq-tools, qq's cache and the PATH line, as "Remove everything" below does. The demo folders ~/qq-try and ~/qq-ci-venv, and the QQ_PYTHON line, are boxes left unticked: they stay unless you tick them.

Step 2 of the page, Set up repos in an org you own, prints the plan for putting an org's repos on qq in your terminal. In a terminal without a browser, add install --only qq to the end of the command: it asks the same questions there, and --dry-run shows the commands without running them.

Today: qq-setup is not on npm yet. It never writes to GitHub, and on your machine it changes only your home folder (and Homebrew's, for the Mac Python step). For an org, it only prints the plan: it creates no repo and changes no setting. The page listens on 127.0.0.1 only and its link works once. qq-setup refuses to open the page while GH_TOKEN, GITHUB_TOKEN or a GitHub Enterprise token variable is set, so it only ever acts as your own gh login.