Put a repo on qq
Onboard a repo in two parts. First make it build and test with qq on your machine, then put it behind the gate so every change lands through the merge queue.
Onboarding has two parts. The first takes minutes and needs nobody's
permission: give the repo an infra/repo.toml and check that qq test
passes. The second puts the repo behind the gate, so its pull requests get a
generated presubmit and land through the merge queue. That part touches
three repos and ends with an org owner applying settings.
A real run: a small Python repo with one test gets its infra/repo.toml
from qqsync init, passes qqsync validate, and passes qq test. As in
the other recordings, Python 3.14.8 is passed with --toolchain because
the sandbox cannot reach ghcr.io.
Part 1: make it build with qq
Pick its kinds
| Kind | Use it for | The repo needs |
|---|---|---|
python-service | a Python server | requirements.txt |
pytest | a Python test suite | requirements-dev.txt listing pytest |
node-app | a Next.js app | pnpm, with build and typecheck scripts |
gatsby-site | a Gatsby site (CI only for now) | pnpm, with build and test scripts |
A repo can have several targets, for example a python-service and a
pytest. Other languages have no kind yet; a new kind is an org-wide change
in infra-config and recipes first.
Write infra/repo.toml
qqsync init writes it for you: one target per kind, the toolchains those
kinds need at the versions toolchains promoted, and the qq version. It needs
checkouts of infra-config and
toolchains for the lists it reads:
git clone -q https://github.com/quirq-ai/infra-config ~/src/infra-config
git clone -q https://github.com/quirq-ai/toolchains ~/src/toolchains
cd ~/my-repo
qqsync init . --kind pytest \
--kinds ~/src/infra-config/config/kinds.toml \
--promoted ~/src/toolchains/promoted.toml \
--qq-version 0.1.0It prints infra/repo.toml: written with target kinds pytest, and never
replaces an existing manifest. The file it wrote (digests shortened here):
schema = "quirq-repo/1"
[qq]
version = "0.1.0"
[toolchains.python]
version = "3.14.8"
platforms.linux-x86_64 = { source = "oci://ghcr.io/quirq-ai/toolchains/python@sha256:32c0…a716", digest = "sha256:230c…b03c" }
[[targets]]
name = "pytest"
kind = "pytest"
cacheable = falseNew targets start with no srcs and cacheable = false. Add srcs (the
files the target is built from, such as ["tests/**", "requirements-dev.txt"]), then delete the cacheable line. Never edit pins
by hand: the toolchain roller moves them.
What a target can say
| Field | What it is |
|---|---|
name | the target's name, unique in the file (required) |
kind | one of the kinds above (required) |
srcs | input globs, relative to the repo root |
outs | declared outputs, relative to the repo root |
deps | other targets in this file that this one needs first |
cacheable | false for a step that is not hermetic: it still runs, but its result is never reused |
params | settings for the kind, passed to its adapter as is |
Every params key is optional:
| Kind | params |
|---|---|
python-service | requirements (default requirements.txt), entry (the script that starts it), port_env (default PORT), ready_path (default /), probes, bench |
pytest | requirements (default requirements-dev.txt), args (extra pytest arguments); shards is accepted and ignored for now |
node-app | dir (the app folder, default .), port_flag (default -p), ready_path (default /), probes, env, bench |
For example, a server that reads its port from APP_PORT and answers on
/health:
[[targets]]
name = "server"
kind = "python-service"
srcs = ["server.py", "services/**", "requirements.txt"]
params = { port_env = "APP_PORT", ready_path = "/health" }The full rules are in sync's
schema,
and each kind's params are documented at the top of its adapter in
recipes.
Check it and test it
qqsync validate infra/repo.toml
qq testqqsync validate prints infra/repo.toml: PASS, or exits 1 and lists every
problem. Unknown keys are errors, target names must be unique, and deps
must name targets in the same file. Then qq test should pass the way it did
in the video. Open a pull request with the new file.
Part 2: put it behind the gate
The repo must be public in quirq-ai. Do these in order:
- infra-config: add the repo to
config/repos.toml, with a presubmit and a post-submit builder inconfig/pipelines.toml. - The new repo: in infra-config, run
python3 tools/qqcfg.py deliver <repo> <path to its checkout>. Add the generated workflows to the pull request from part 1, and merge it. - gate: add a
[[repo]]entry tosettings/github.toml, and move the infra-config commit inpins.tomlto one that lists the repo. - Release access: install the release executor App on the repo and add
it to gate's
executor_repos, before release moves its infra-config pin past step 1. Without it, release's lkgr job fails for every repo. - An org owner applies the settings at the gate commit they are given.
The script shows a dry run, asks them to type
yes, and writes only what they saw:
( mkdir -p ~/qq-apply && cd ~/qq-apply && rm -rf qq-gate && git clone -q https://github.com/quirq-ai/gate qq-gate && cd ./qq-gate && git checkout -q <COMMIT> && scripts/apply.sh )From then on, every pull request gets the <repo>-presubmit check, and
main lands only through the merge queue. Dependency rolls (Dependabot and
the toolchain roller) are optional and can come later. The owner's steps are in
gate's apply guide.
Who approves what: a policy change in infra-config is a pull request
there. By policy, suraj approves changes to its config/, schema/,
tools/, generated/, tests/ and .github/. Only an org owner can
apply gate settings; an agent cannot.
Onboarding repos in your own org
qq-setup (see Install qq)
has this as step 2 of its page, Set up repos in an org you own. You pick an
org and the repos to put under qq. It offers only repos that can already run
their kind's commands, warns about existing branch protection in qq's way, and
prints the plan with how to undo it.
Today: it prints the plan and stops. It creates no repo, opens no pull request and changes no setting. The version that carries the plan out comes after review, and v0 sets up public repos only.
After it lands
What happens to your change on main. The post-submit build, the tree status, lkgr, the daily canary, installing from a channel, and the dashboard that shows it all.
Commands by type
Every qq command grouped by what you use it for, with exit codes and environment variables, plus the tools behind the infra.