a73x

docs/development.md

Ref:   Size: 5.5 KiB   History

# Development commands

```sh
mise install                  # install/pin Zig 0.15.2 from mise.toml; one host install is shared across worktrees
make mac-sdk                  # Darwin only, and `make build` runs it: a shadow SDK
                              # under deps/mac-sdk, because zig 0.15.2 cannot link
                              # the stub Xcode 26.4+ ships. No-op elsewhere.
make build test e2e          # build lints first; Makefile resolves ZIG via mise (or `ZIG=/path/to/zig`)
make lint                    # standalone: fetch/verify pinned zlint and lint Zig sources
make check                   # lint + fmt + tests + shell/web ABI/source checks — pre-commit gate
make ci                       # check + e2e + agent + throughput — the delivery gate
make daemon-test client-test  # focused component tests; same artifacts as make test
make native-core-test         # GUI workspace/interaction tests without window/font libraries
make agent soak bench throughput
make native native-e2e         # opt-in muxg; SDL3/freetype/fontconfig/HarfBuzz + GL headers; e2e also needs python3
make vm                       # real user journeys against the mux-e2e VM (test/vm.sh)
make mac xos                  # macOS journeys (test/mac.sh); the cross-OS gate (test/xos.sh).
                              # Both take their boxes BY NAME and have no default
                              # for one: MAC_BOX (macOS, no toolchain, SCRUBBED),
                              # MAC_BUILDER (a Mac with zig + deps/mac-sdk, builds
                              # only, never scrubbed, defaults to $MAC_BOX), and
                              # for xos also LINUX_BOX (x86_64 Linux VM, scrubbed).
make provision-mac            # clone, boot and key a macOS guest on a tart host and
                              # print one line; `eval "$(test/provision-mac.sh)"`
                              # is how MAC_BOX gets set. --down takes it away.
make install                  # mux + muxg -> ~/.local/bin, ReleaseSafe; needs native libraries
                              # MUX_TARGET follows the HOST: a Mac installs a Mac
                              # binary, because that is the only one it can link
make release release-mac      # one tarball per OS into dist/, cut on that OS;
                              # release-mac runs `make release` on $MAC_BUILDER
make xversion-build xversion  # cross-version gate; XVER_OLD_WORKTREE points at the old checkout (default ..)
```

First build after a clean checkout fetches ~30MB of QUIC deps (minutes, once).
`deps/quic/out` holds the generated link-time outputs; `deps/quic/work` is the
local build workspace and cache. In multi-worktree workflows, you can copy a
same-revision/same-platform `deps/quic/out` tree from another worktree to avoid
re-downloading, but keep `deps/quic/work` local per-worktree: it contains
absolute-path build caches and should not be shared via mutable symlinks.
`make clean-deps` removes `deps/quic/out` and `deps/quic/work`; `make clean`
deliberately spares `deps/quic`.

## Lint dependencies

`make lint` fetches zlint v0.9.1 from the upstream release into `deps/zlint/`,
verifies the host asset against its pinned SHA-256 checksum, and runs it over
all repository Zig sources, including tests and build tools. Cached copies
are checked too. Downloads are staged and renamed only after verification.
Linux x86-64/ARM64 and macOS Intel/Apple Silicon are supported.
The bootstrap requires curl and either sha256sum or shasum.

`zlint.json` enables rules that can fail the build. We deliberately leave
`no-print` off: terminal programs and test fixtures have legitimate output.
`unsafe-undefined` and `suppressed-errors` need an ownership/error-handling
review before adoption; enabling them globally would encourage blanket
suppressions. `no-catch-return` in v0.9.1 incorrectly flags our optional-error
return values. `duplicate-case` flags intentionally separate switch arms with
identical bodies. These are not enabled to avoid unrelated style churn.

`make check` requires ShellCheck and Node.js. Install them with the host's
package manager (for example, `apt install shellcheck nodejs` on Debian/Ubuntu
or `brew install shellcheck node` on macOS). Missing tools fail their checks;
a fresh machine cannot silently skip shell lint or web ABI verification.
The compiler and linter versions are pinned; ShellCheck currently gates errors
only, so its installed version should be recorded when investigating a failure.

## Ad hoc reproductions and logs

Use `tools/isolated-run.sh PATH_TO_MUX COMMAND [ARG ...]` for a reproduction.
It exports isolated XDG directories and `MUX`, and stops the daemon on its
isolated default socket before removing the directories. A script that creates
additional custom sockets remains responsible for stopping those daemons.

Use `tools/run-logged.sh LOG COMMAND [ARG ...]` to capture a noisy check. It
prints the final 30 lines and returns the command's original exit status.

Native tests keep ordinary pane, input, resize, clipboard and font checks in
`make native-e2e`'s single shared journey. Focused scripts retain exceptional
cases such as delayed replies, lifecycle failures, real SSH and compositor
scaling. Their workspace helpers create the required panes without replaying
the persistence scenario first.

Native fixture directories are removed after successful runs. Failures retain
their screenshots, state and logs; set `MUXG_TEST_KEEP_ARTIFACTS=1` to retain a
successful run too. Only the fixture's own temporary directory is removed;
the command log passed to `tools/run-logged.sh` is separate and remains available.