Adopt CVSM
Adopting CVSM means copying a set of tracked files into your repo, filling in a few project values, and turning on branch protection once. An agent in your session can do every step; you decide, and you provide an admin account where one is needed.
Before you start
Section titled “Before you start”- A GitHub repo whose default branch is
main, and an account with admin rights on it. git, the GitHub CLIgh, and Python 3.11 or later (the scripts read TOML withtomllib; CI uses 3.12).- A local clone of CVSM, written
<cvsm clone>below. - Branch protection on a private repo needs a paid GitHub plan (e.g. Pro or Team). Public repos don’t.
The five steps
Section titled “The five steps”-
Copy the CVSM files, then adapt
guard.toml,run.tomland your training code’s config output.Copy only tracked files. That way untracked local files in the CVSM clone (tool configs,
__pycache__) stay behind, and the.claude/skillssymlink survives. The exclusion leaves outpages.yml, which builds CVSM’s own docs site:Terminal window git -C <cvsm clone> archive HEAD AGENTS.md .agents .claude .codex .github scripts tests ':!.github/workflows/pages.yml' | tar -x -C <your repo>If your repo is published or shared, also keep a copy of CVSM’s licence with these files, e.g. as
.github/CVSM-LICENSE(see License).Then merge the lines of CVSM’s
.gitignoreinto yours. You can delete tests intests/that you won’t use. Note which CVSM commit you copied (git -C <cvsm clone> rev-parse HEAD) in the message of the adoption commit, so you can compare later CVSM improvements against it.- Edit
.github/guard.toml:- Add your directories to
layout(e.g.src/**,configs/**). Also add the root files the project changes, such aspyproject.toml, lock files likeuv.lock, and.python-version. If you miss one, guard rejects PRs that change dependencies. - Add your eval and data paths to
protected. - Adjust
markdownas needed.
- Add your directories to
- Edit
scripts/run.toml:experiment,env_lock(your lock files) andgpus.- Data directories are usually ignored by git, so the data fingerprint comes from a tracked data manifest: a file listing each data file’s checksum, e.g. the output of
sha256sumsaved asdata.sha256. - Put its path, relative to the repo root, in
data_manifest, and add it to bothlayoutandprotectedinguard.toml.
- Data directories are usually ignored by git, so the data fingerprint comes from a tracked data manifest: a file listing each data file’s checksum, e.g. the output of
- Make your training code write its full resolved config as a JSON object to
$RUN_DIR/config.jsonat start, from one process only (e.g. rank 0).- Include every setting that can affect results, derived ones too, such as the effective batch.
- The keys in a study spec are this config’s flattened dotted keys (e.g.
optim.lr). The results command uses them to check each run against the spec. - Leave out values that differ per run without affecting results, such as output directories, run names and timestamps. Otherwise every results comment lists them as
未声明的差异(undeclared differences). If you must include one, declare it Adaptable in the spec.
- If several users share one machine and
TMPDIRis per user, each user’s default GPU lock directory sits in their ownTMPDIR, and they can’t see each other’s locks. Setlock_dirinrun.tomlto one local directory they can all write to. - If you have a
CLAUDE.md, condense the project facts into the Project section ofAGENTS.md(one line per field). Move the rest intodocs/or code comments, then deleteCLAUDE.md. CVSM reads onlyAGENTS.md, and guard rejects.mdfiles elsewhere.
- Edit
-
Fill in the Project section of
AGENTS.md, one line per field.Leave the other sections as they are.
AGENTS.mdis at most 80 lines (a test checks this), and each field is one line:Layout: how the code directories divide, and where the shared code and the method modules live.Test: the test command, the same one CI runs.Language: the language of human-facing text (see Language).Protected eval/data paths: eval and data paths agents may not change at will. These matchprotectedinguard.toml.Run: the Run command and the results-comment command.- Runs launch in a fresh worktree (
../worktrees/N-<slug>) that has no ignored.venvor data directories. So the commands must work as they are in a new worktree, in an environment with both the project’s dependencies and MLflow. - With uv, put
mlflow-skinny,sqlalchemyandalembicin the dev dependency group (uv add --dev;uv runincludes the dev group by default). - Then write
uv run python scripts/run.py --issue N -- <cmd>, and the results command asuv run python scripts/results.py --issue N(results.pyneeds MLflow too). - Find data through absolute paths, environment variables or tracked symlinks.
- Runs launch in a fresh worktree (
Run records: which MLflow backend run records go to.
-
Install your CI dependencies in
.github/workflows/test.yml.Edit the
pip installline in.github/workflows/test.ymlto install your project’s dependencies and test tools, and keep the test command the same asTestinAGENTS.md. If the project uses uv, CI can still install dependencies with pip and run the same tests.- The copied rule, skill and guard tests need
pyyaml. - If you keep the tests of
scripts/run.py, install MLflow too. The reference setup installsmlflow-skinny, plussqlalchemyandalembicfor SQLite. - CI runners have no GPU. If your lock file has a CUDA build of torch, install the CPU build in CI instead (
pip install torch --index-url https://download.pytorch.org/whl/cpu). Install it before the project’s dependencies, because a CUDA build that is already installed won’t be replaced by one installed later. - Don’t rename the jobs
guardandtest. Branch protection finds the checks by these names.
- The copied rule, skill and guard tests need
-
Push to main, then run
scripts/setup.shas an admin.The default branch must be called
main;setup.sh, guard and the skills all assume it. If an older repo usesmaster, rename it on GitHub first.Push the changes above to main directly, as one adoption commit. Two things make this necessary:
- guard runs on
pull_request_target, so it uses the version on main. - Until main has both the
guardandtestworkflows, the required checks would block every PR.
This is the only exception to “never push to main” in
AGENTS.md, and you do it once, before protection is on. After the push, thetestworkflow runs once on main; confirm on the Actions page that CI passes.Then, from the repo root and logged in to gh as the human admin (not the machine account), run:
Terminal window bash scripts/setup.sh # defaults to the repo of the current directorybash scripts/setup.sh owner/repoIt does the following:
- Creates five labels:
study,plan,code,runandneeds-decision. - Allows only squash merges, with the PR title as the commit title and an empty body, and deletes branches after merge.
- Protects main: changes go through PRs,
guardandtestmust pass, 0 approvals, no bypass even for admins, and no force pushes or deletion.
Running it again is safe, and it keeps other labels you already have. Branch protection, though, is overwritten as a whole: protection settings the project added later (e.g. required approvals) are reverted on a rerun.
- guard runs on
-
Check that both agents load the rules: Codex and Claude Code.
- Codex reads
AGENTS.md, skills from.agents/skillsand rules from.codex/rules.- Codex reads the project’s
.codex/only once it trusts the project. Runcodexinteractively once at the repo root and accept the trust prompt. (codex exec -s danger-full-accessmarks the project trusted without a prompt.) codex execpolicy check --rules .codex/rules/cvsm.rules gh pr merge 1checks only the rules file itself, and should printforbidden.- To confirm a session really loaded the rules, open a Codex session in the repo and ask it to run
gh pr merge --help. The rule should block it; even if allowed, this command merges nothing. Also confirm that all four skills are listed.
- Codex reads the project’s
- Claude Code reads
AGENTS.md, reads skills through the.claude/skillssymlink, and.claude/settings.jsondeniesgh pr merge. Open a session in the repo and confirm that all four skills are listed.
- Codex reads
Optional: a machine account for the agents
Section titled “Optional: a machine account for the agents”If you want GitHub to separate your actions from the agents’, let all agents share one machine account:
- Add it as a repo collaborator with write access, not admin.
- Create a classic token for it with the scopes
repo,workflowandread:org. A fine-grained token can’t act as a collaborator on a repo someone else owns. - Log it in to a separate directory with
GH_CONFIG_DIR=<dir> gh auth login, and have agents use it in this repo only.-
Two local files point
GH_CONFIG_DIRat<dir>. List both paths in.git/info/excludeso they stay out of the repo. -
Both files live only in the main clone, not in worktrees. A session started from the main clone passes the setting to the agents it starts. If you open a session directly in a worktree, put copies there first.
-
.claude/settings.local.json:{"env": {"GH_CONFIG_DIR": "<dir>"}} -
.codex/config.toml:[shell_environment_policy]set = { GH_CONFIG_DIR = "<dir>" }
-
- Commit as that account too.
- In the repo, run
git config user.name <account>andgit config user.email <id>+<account>@users.noreply.github.com. Look up<id>withgh api users/<account> -q .id. - Use an HTTPS remote and run
gh auth setup-gitonce, so pushes go through gh’s login. It writes the global git config, so the account it uses depends on theGH_CONFIG_DIRset at the time.
- In the repo, run
- If an agent runs on another machine, log in with this token there too.
- Admin tasks (running
setup.sh, changing branch protection) still use your own account.