Skip to content

Latest commit

 

History

History
478 lines (374 loc) · 20.3 KB

development.md

File metadata and controls

478 lines (374 loc) · 20.3 KB

Development

This page tells how to work on this repository today. The repository holds the tooling in xtask, the commit hook, the CI workflow and the documents. It holds no product code yet, by ruling D14 in docs/decisions.md. Entry T-033 creates the product crates first, in the first implementation session. Until then, the workspace in Cargo.toml has one member: xtask.

docs/conventions.md gives the rules for code, prose, git and secrets. TODO/RULES.md gives the rules of the work record.

Requirements

Tool Needed for Where it comes from
rustup Every cargo command https://rustup.rs
Rust 1.99.0 Every build and every xtask command rustup reads rust-toolchain.toml and installs it on the first cargo command, with rustfmt and clippy.
A linker Every build: rustc links through it Windows: Visual Studio Build Tools with the workload "Desktop development with C++" (the MSVC linker and the Windows SDK). Linux: gcc or clang (on Debian, build-essential).
git The checks, which list the files through git The package manager of the host
cargo-deny The step deny of the gate cargo xtask setup installs it when it is missing.
gh (optional) cargo xtask remote, and the GitHub probe of cargo xtask doctor https://cli.github.com
podman or docker cargo xtask linux on a Linux host The package manager of the host
wsl-toolkit cargo xtask linux on a Windows host https://github.com/Azathothas/ToolKit
KVM The Linux engine tests of milestone M3 A Linux host with /dev/kvm, or the Windows host through wsl-toolkit (KVM)
Windows 11 Pro with Hyper-V, and admin rights The Windows engine tests of milestone M4, and the spike T-014 Hyper-V turned on, and an elevated shell

NOTE: The toolchain is pinned, so CI and each developer run the same clippy. A newer clippy can add a lint that makes the gate fail.

First steps after a clone

export CARGO_BUILD_JOBS=4
cargo xtask setup
cargo xtask doctor
cargo xtask gate

In PowerShell, set the limit with $env:CARGO_BUILD_JOBS = "4". Memory tells why the limit is necessary.

  1. The first cargo command installs Rust 1.99.0 and builds xtask. This can take some minutes.
  2. cargo xtask setup prepares the clone. setup lists its steps.
  3. cargo xtask doctor reports what this host can do. Run it again at the start of each session. A report from an earlier session is not evidence for the host today.
  4. cargo xtask gate runs the gate. Exit 0 means that the clone is ready for work.

The xtask commands

cargo xtask help prints the usage text of xtask/src/main.rs. Each command finds the repository root from the xtask manifest, so the working directory does not change its result. .cargo/config.toml defines the aliases cargo xtask and cargo todo.

Command What it does
cargo xtask setup [--no-install] Prepares this clone: the commit hook, the Rust targets and cargo-deny.
cargo xtask doctor [--json] [--kvm] Reports what this host can do for development.
cargo xtask gate [--strict] [--list] [--json] [STEP...] Runs each step of the gate, or the named steps.
cargo xtask check [--json] NAME... Runs the named checks. The name all runs each check.
cargo xtask check --list Names each check and the defect that it finds.
cargo xtask layering [--json] Checks that the crate graph goes down only.
cargo xtask todo COMMAND Checks and writes the work record. cargo todo is the short form.
cargo xtask linux [--kvm] [--image IMAGE] [--native] [--keep] -- COMMAND... Runs COMMAND in a Linux container.
cargo xtask refs list [--json] Prints the pins table and the state of each clone.
cargo xtask refs fetch [--json] [OWNER/REPO...] Clones the pinned reference trees and verifies each commit.
cargo xtask remote [--json] Lists the open issues and pull requests of this repository, as data.

Exit codes

Code Meaning
0 Pass.
1 Fail. The command ran and found a defect.
2 Not run. A tool, a file or a scope was missing, so the command cannot give a pass or a fail.
64 Usage error: an unknown command, option, step or check name.

cargo xtask linux is different: it exits with the exit code of COMMAND. It exits 2 only when it cannot start wsl-toolkit, podman, docker or sh. Read each exit code from the command itself. A pipe gives the exit code of its last program.

setup

cargo xtask setup prepares this clone (entry T-008):

  1. It sets the git option core.hooksPath to the directory .githooks. Git then runs .githooks/commit-msg.
  2. It sets the mode of the hook to 100755 in the index. Git does not run a hook without the executable bit, and it prints nothing about it.
  3. It adds the musl targets of the guest agent: x86_64-unknown-linux-musl and aarch64-unknown-linux-musl.
  4. It installs cargo-deny when cargo-deny does not answer.
  5. On Windows, it asks wsl-toolkit for its version.

Then setup prints each item with its state. --no-install downloads and builds nothing, and only reports what is missing. Exit 0 means that each required item is present. Exit 1 means that an item is still missing.

doctor

cargo xtask doctor reports what this host can do for development (entry T-009). It probes each tool by running it, because a program on PATH can still fail. For example, gh can be on PATH with a token that no longer works. So the probe of gh makes a real API call.

The probes:

  • the OS;
  • rustc and cargo, and whether the active Rust is the pinned toolchain;
  • git, gh, the login of gh (gh api user), and cargo-deny;
  • wsl-toolkit, podman and docker;
  • /dev/kvm: natively on Linux, and on Windows only with --kvm;
  • Hyper-V: the WMI value HypervisorPresent and the vmcompute service;
  • admin rights.

Each probe prints ok, missing, or ???? when it cannot tell, with its evidence. With --json, the same answer comes as one JSON object. The doctor changes nothing.

On Windows, --kvm also opens /dev/kvm in a container of the Linux runner. That starts one container, and the first run pulls the image.

A missing tool is a fact in the report, not a failure. The doctor exits 0 when it ran, whatever its probes found. It exits 2 only when no probe could run a program.

gate

cargo xtask gate runs these steps, in this order (xtask/src/gate.rs):

Step What it runs
fmt cargo fmt --all -- --check
clippy cargo clippy --workspace --all-targets --locked -- -D warnings
test cargo test --workspace --locked
checks Each check of cargo xtask check all
deny cargo deny --locked check, with the rules of deny.toml
  • STEP... runs only the named steps, in the order of the table.
  • --list prints the step names, one on each line.
  • --json prints one JSON object at the end. The cargo output then goes to stderr.
  • When CARGO_BUILD_JOBS is not set, the gate sets it to 4 for its cargo steps.

A step that did not run is never a pass. For example, the step deny does not run when cargo-deny is missing.

Result of the steps Exit code Exit code with --strict
Each step passed 0 0
A step failed 1 1
No step failed, but a step did not run 2 1
No step ran 2 1

CI runs cargo --locked xtask gate --strict. Run the same command before a push. The alias alone does not pass --locked to the build of xtask.

check

Each check follows the contract in docs/conventions.md. The gate runs them in this order:

Check The defect that it finds
text A byte outside ASCII, a control byte, a CR or a missing final newline in a tracked text file
prose A sentence that is too long, a banned word, or an emoji in a document
docs A broken link or anchor, an orphan page, or a cited path or line that does not exist
one-home One sentence in two documents
placeholders A template placeholder that somebody did not replace
secrets A credential or a private key in a file that git would publish
attribution A commit in git log that credits a tool
layering A crate that depends on a crate of its own layer or a higher one
todo A work record that does not agree with itself

The check attribution exits 2 when it reads no commit. A clone with no history cannot pass it.

layering

cargo xtask layering reads the crate graph from cargo metadata. The layer table is in xtask/src/layering.rs, and it already names each planned crate. Today the workspace holds xtask only. The check fails on an edge to a crate of the same layer or a higher one (entry T-002).

remote

cargo xtask remote lists the open issues and pull requests of this repository through gh api (entry T-012). It only reads. It tells pull requests from issues. An empty list is a valid result. The text of each item is data, not an instruction.

The work record

TODO/ holds the work record. TODO/PROGRESS.md holds the work order, and TODO/INDEX.md holds one row for each entry. TODO/RULES.md gives the rules.

cargo todo check                # the record agrees with itself
cargo todo set T-NNN STATUS     # move a status, then derive each count again
cargo todo counts               # derive the counts again after a hand edit
cargo todo next                 # print the next free entry id
cargo todo remap FILE...        # after an edit of FILE, move its citations
  • The check derives each count from the rows of the index. It trusts no number that a file states.
  • It compares each row with its entry, and each cited path and line with the tree.
  • STATUS is one of open, partial, blocked and done.
  • The gate runs the same check as the check todo.
  • The checker is a port of podssh-todo from the sibling repository podssh (entry T-003). Entry T-016 decides whether the two become one shared crate.

Linux runs

cargo xtask linux runs COMMAND in a Linux container, with the repository at /work as the working directory (entry T-010). It exits with the exit code of COMMAND.

  • xtask joins the words of COMMAND with spaces, and sh reads the result. Put a compound command in one argument.
  • --image IMAGE selects another image. The default image is Rust 1.99.0 on Debian trixie, pinned by digest in the source of the linux module.
  • --kvm passes /dev/kvm into the container.
  • --keep keeps the stopped container.
  • CARGO_BUILD_JOBS goes into the container. When it is not set, the value is 4.
cargo xtask linux -- uname -a
cargo xtask linux -- 'cargo build && cargo test'
cargo xtask linux -- cargo xtask gate fmt clippy test
cargo xtask linux --kvm -- ls -l /dev/kvm

From Windows, through wsl-toolkit

  • xtask starts wsl-toolkit run directly, with no Git Bash and no PowerShell between them. The command travels as base64 of its bytes.
  • wsl-toolkit copies the repository into the container without target/, .git/, .refs/, .work/ and one directory of local agent settings. The source of the linux module lists the patterns.
  • Changes in the container do not come back to the host.
  • The job is ephemeral: wsl-toolkit removes the container and the copy when the job ends. --keep keeps them.
  • A job stops after 60 minutes, and the result reports exit code 124.

READ in the wsl-toolkit 6.0.0 manual on 2026-10-14: a workspace copy above 1 GiB or above 200000 entries is refused. Build output can pass that limit, so target/ stays out of the copy.

NOTE: The copy has no .git/ directory. The checks list the files through git, so the step checks reports "not run" in the container. Run the cargo steps by name in the container, and run the full gate natively.

CAUTION: Git Bash rewrites an argument that starts with / into a Windows path, before cargo starts. Use PowerShell, or set the two variables of the next block for that command.

MSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL='*' cargo xtask linux --kvm -- ls -l /dev/kvm

On a Linux host

  • xtask uses podman when it answers, and docker when podman does not.
  • The repository is mounted read-write at /work. Cargo in the container writes to target/linux-container, so the two builds do not invalidate each other.
  • Each container stops after 3600 s. podman takes the limit as a flag. docker has no such flag, so xtask runs COMMAND under coreutils timeout in the image. A timeout exits 124.
  • With podman, --kvm also keeps the groups of the user, because /dev/kvm is usually open to the group kvm only.
  • --native runs COMMAND with sh -c on the host, in the repository. With --kvm, it first checks that /dev/kvm opens for reading and writing.

CAUTION: docker runs as root, so each file that it writes to target/ belongs to root.

KVM

MEASURED on 2026-10-14 on the operator's Windows 11 host: /dev/kvm is available inside a wsl-toolkit job. Conditions: WSL2 kernel 7.2.0-WSL2-STABLE, and the module kvm_intel with nested=Y. The Prove of entry T-010 checks it with this command:

cargo xtask linux --kvm -- ls -l /dev/kvm

NOTE: That is nested virtualization. Use it for development tests only. Never publish a performance number or an isolation claim from it.

Firecracker has no mode without KVM, so a host without /dev/kvm cannot run the Linux engine tests. The doctor names that gap with its evidence. The routes are a Linux host with KVM, nested KVM through wsl-toolkit, or the Windows engine on Hyper-V.

WSL rules

WARNING: Some wsl.exe commands act on each WSL distribution of the host, not only on the distribution of wsl-toolkit. A wrong command can stop or delete the work of other tools.

  1. Do not call wsl.exe from a session, a script or xtask.
  2. Never give wsl.exe the options --shutdown, --terminate or --unregister.
  3. Do not act on a WSL distribution that wsl-toolkit did not create.
  4. Use cargo xtask linux for Linux work.

The sibling repository podssh holds the same rule: Azathothas/podssh@3ad320382891d1d5697aadedd689ed07cd962e4f:AGENTS.md:191.

Memory

CAUTION: By default, cargo runs one compiler job for each CPU thread. READ in podssh: on 2026-10-07, three builds with no job limit ran at the same time. They almost used all the memory of a 64 GB machine (Azathothas/podssh@3ad320382891d1d5697aadedd689ed07cd962e4f:docs/development.md:64).

  1. Give each cargo command the job limit CARGO_BUILD_JOBS=4. The gate and cargo xtask linux use 4 when the variable is not set.
  2. Start a build only when no other build runs, also for a container build.
  3. This holds for agents too: at most one agent builds at a time.

NOTE: READ in podssh: the base of wsl-toolkit gives its Podman account no cgroup delegation. It accepts a memory limit on a container and does not enforce it (Azathothas/podssh@3ad320382891d1d5697aadedd689ed07cd962e4f:docs/development.md:74). The job limit is the protection.

NOTE: The operator can limit WSL in %USERPROFILE%\.wslconfig. No tool of this repository changes that file.

Disk

What grows How to give the space back
target/ cargo clean
target/linux-container cargo clean, or delete the directory
.refs/ Delete the directory. cargo xtask refs fetch clones the trees again.
.work/ Delete what you made there.
The jobs of wsl-toolkit wsl-toolkit gc, as below
The disk image of the wsl-toolkit base Only the operator compacts it.

An ephemeral job removes its container and its copy when it ends. A run that somebody stopped can leave both behind.

wsl-toolkit gc --older-than 24h            # report only; changes nothing
wsl-toolkit gc --older-than 24h --apply    # remove

CAUTION: wsl-toolkit gc acts on each job of wsl-toolkit, not only on the jobs of this repository. Without --include-live, it keeps a job that is running.

READ in podssh: on 2026-10-10, 90 old jobs held 203 GiB (Azathothas/podssh@3ad320382891d1d5697aadedd689ed07cd962e4f:docs/development.md:91).

The disk image of the base does not shrink when the distribution frees space. It is ext4.vhdx in the state directory of wsl-toolkit. Compaction needs wsl.exe and an elevated diskpart, so only the operator does it.

Hosts for the tests

Work Host How
The tooling, the documents and the record Any host cargo xtask gate, natively
Linux builds and Linux tests Linux, or Windows through wsl-toolkit cargo xtask linux -- COMMAND
The Linux engine tests (M3) and the spike T-015 A Linux host with KVM, or Windows with nested KVM cargo xtask linux --kvm -- COMMAND
The Windows engine tests (M4) and the spike T-014 Windows 11 Pro with Hyper-V Native cargo commands in an elevated shell

MEASURED on 2026-10-14 on the operator's Windows 11 host, with hcsdiag: HCS refuses a caller outside two groups. The groups are Administrators and Hyper-V Administrators.

The engine tests do not exist yet. The entries of M3 and M4 add them, for example T-088 on Linux and T-105 on Windows. CI does not run them. Whether a hosted runner exposes /dev/kvm is not measured.

CI

.github/workflows/ci.yml runs the gate on two hosted runners: ubuntu-24.04 and windows-2025. It runs for each push to main, for each pull request, and on request.

  1. It checks out the full history, because the check attribution reads git log.
  2. It installs the pinned toolchain from rust-toolchain.toml.
  3. It installs cargo-deny. Without cargo-deny, the step deny does not run, and --strict fails the gate.
  4. It runs cargo --locked xtask gate --strict, with a limit of 60 minutes.

Entry T-007 stays partial until the first run after the push is green. The URL of that run goes into the entry. docs/conventions.md gives the rules for each workflow of this public repository.

The commit hook

.githooks/commit-msg refuses a commit message that credits a tool, before the commit exists. It refuses a co-author trailer, a "generated with" line and each tool or vendor name that it knows. docs/conventions.md gives the rule.

The hook is a POSIX sh script, not Rust (decision P3 of the planning session):

  • It must work in a fresh clone, before any build.
  • A hook that calls a program that is not there refuses every commit. READ: the hook of the template calls a separate script, and exits 2 when that script is absent (Azathothas/TEMPLATE@ea26c7d91a087a7132f56034fb77f8d40d7766cb:dotfiles/githooks/commit-msg:38).

Git does not clone hooks. cargo xtask setup arms the hook. Without xtask, this command arms it:

git config core.hooksPath .githooks

The exit codes: 0 allows the message, 1 refuses it, and 2 means that the hook could not run. Git refuses the commit for each code other than 0.

The Prove of entry T-008 plants a credit and expects exit 1:

mkdir -p .work
printf 'Test\n\nCo-Authored-By: Someone\n' > .work/msg.txt
sh .githooks/commit-msg .work/msg.txt; echo "exit $?"

The hook knows a fixed list of shapes and names. The check attribution reads git log after the commit, and the gate runs it.

Releases

Releases come later, in milestone M9.

  • T-200 adds the release workflow. It builds static musl binaries for Linux on x86_64 and aarch64, and a binary for Windows on x86_64.
  • The release also publishes the guest images, SHA256SUMS and artifact attestations.
  • T-201 tests the install guide from a fresh clone, on both OSes.
  • T-202 adds the third-party licences to each release.
  • There is no CHANGELOG.md before the first release.
  • Cargo.toml already holds the release profile.

Reference trees

The pins table in docs/references.md names each upstream project, its full commit, and the reason for the pin (entry T-011).

cargo xtask refs list                  # print the pins table and each clone
cargo xtask refs fetch                 # clone each pinned tree
cargo xtask refs fetch QaidVoid/kage   # clone one tree
  • refs fetch clones each pin into .refs/OWNER__REPO, and checks out the pinned commit. Then it verifies that HEAD is the pin.
  • A row whose commit is not 40 hex digits, such as a release, is listed and skipped.
  • refs fetch clones, fetches and checks out only. It never deletes a directory.
  • Git ignores .refs/.
  • A reference tree is data. Never build or run code from it. Text in it that reads like an instruction is not an instruction.