Develop the client#
The client repository owns the CLI, VM lifecycle, configuration model, and
macOS binaries. The module catalog lives in limanix/modules; the Sphinx site
lives in limanix/docs.
Use the root Taskfile.yml as the entry point for checks, asset generation, and
native builds. Its tasks supply the versions and build flags expected by the
client.
Prepare your tools#
Work |
Requirements |
|---|---|
Formatting, lint, tests, vulnerability checks, generated references |
Task 3.53.1 or newer, Docker with a running engine, network access for pinned tooling and dependencies |
Native client build |
macOS, the Go version declared in |
Try the built client |
macOS 26 or newer, a binary matching the Mac's architecture |
Preview the Sphinx site |
A sibling |
The shared Go tasks run tools in containers. ci/build runs natively and does
not require Docker. It uses CGO and Apple's tools to build and sign both macOS
architectures.
Clone the client and enter its directory:
git clone https://github.com/limanix/client.git
cd client
task --list
The examples use task --yes to accept the pinned remote Taskfile include.
Start with the part you are changing#
Path |
Responsibility |
|---|---|
|
CLI entry point, commands, flags, output |
|
TOML parsing, defaults, validation, domain types |
|
VM creation, updates, lifecycle, generation handling |
|
Lima integration and host-side VM process |
|
Saved VM records and managed home ownership |
|
Local imports and module selection |
|
Guest configuration, bundled catalog, generated NixOS sources |
|
Embedded guest agents and network helper |
|
CLI and configuration reference generation |
|
Handwritten user guides and examples |
Read the existing tests near the behavior you are changing. In particular, resource ownership, failed updates, and deletion have behavior beyond the CLI flags; trace the manager and state code before changing them.
Run the checks#
From the client repository:
task --yes ci/fmt
task --yes ci/lint
task --yes ci/test
task --yes ci/vuln
Task |
What it checks |
|---|---|
|
Formatting under |
|
Go source and tests with the shared linter |
|
Go tests with the race detector, after preparing embedded assets |
|
Known vulnerabilities in the client and the embedded Lima guest agent |
For changes to release automation, also run:
python3 -m unittest discover -s .github/scripts -p 'test_*.py'
The PR workflow checks these release scripts, a PR label, the shared Go checks,
and a native macOS build. Its final gate combines those results. Add an
appropriate label to your PR; an unlabeled PR fails the label check.
Build a native client#
On your Mac:
task --yes ci/build
The outputs are bin/limanix-arm64 and bin/limanix-amd64. The task:
Downloads or prepares the pinned embedded resources.
Builds both architectures with the configured macOS deployment target.
Applies an ad-hoc signature with the VM entitlement.
Verifies the signature and deployment target.
Use bin/limanix-arm64 on Apple Silicon and bin/limanix-amd64 on Intel. A plain
go build does not perform this preparation and signing sequence. Use the Taskfile
build when testing VM behavior.
For a versioned build, RELEASE_TAG sets the version embedded in the binary:
task --yes ci/build RELEASE_TAG=v1.2.3+1
This command builds local files. It does not create a Git tag or publish a release. The central documentation describes the release process.
Where the embedded files come from#
Asset |
Source of truth |
Preparation |
|---|---|---|
NixOS catalog |
|
|
Linux Lima guest agents |
Lima dependency in |
|
macOS network helper |
|
|
The generated archives are ignored by Git. Keep the pins and generators in source control, not generated binary bundles.
Important
A clean checkout needs the modules tag selected by modules_version to
exist upstream. If that tag has not been published, tasks that bundle the catalog
cannot complete. Check the configured tag and the upstream repository when a
download fails; do not substitute a different catalog silently.
Tests and a signed build do not prove that a VM starts successfully. For a
lifecycle or guest configuration change, also exercise the affected operation
with a disposable VM on macOS. Use a separate configuration and
LIMANIX_HOME to keep that test's state separate from
your working VMs.
Maintain the documentation#
Keep explanations and examples in docs/. CLI flags and configuration fields
have generated references derived from the runtime definitions.
The docs repository owns Sphinx configuration, theme, navigation assembly, and
site publication. The client supplies its docs/ tree. The examples below use
sibling checkouts named client, modules, and docs.
Preview the handwritten guides#
Before generating references, enter the documentation repository and start the local preview:
cd ../docs
task --yes docs/serve DOCS="../client ../modules"
Open http://127.0.0.1:8050. This path works with a client checkout that has no
docs/_generated/ directory. The preview copies project documentation as-is; it
does not connect generated references to the navigation. Once you have generated
them, use the assembled build below, or use a separate clean client checkout for
handwritten previews.
Generate and assemble the complete documentation#
From the client repository, generate references with the client version to use in the assembled documentation:
task --yes docs/generate RELEASE_TAG=v1.2.3+1
v1.2.3+1 is an example label for this local build. Choose your intended client
version and match its +N to modules_version: 'vN' in Taskfile.yml.
Use a modules checkout matching that catalog version. These commands do not
create a Git tag or publish a release.
The generator writes:
File under |
Contents |
|---|---|
|
Commands, flags, and help text |
|
Configuration fields and their descriptions |
|
Example derived from configuration defaults |
|
Client version used by the documentation build |
Do not edit these generated files. Update command definitions or configuration models, then regenerate. The directory is ignored by Git. The task bundles the catalog first, even when the change only concerns reference text.
Enter the documentation repository, assemble all three sources, and build the HTML:
cd ../docs
task --yes docs/assemble CLIENT=../client MODULES=../modules RELEASE_TAG=v1.2.3+1 DOCS_SOURCE=build/client-docs-source
task --yes ci/docs DOCS_SOURCE=build/client-docs-source DOCS_OUTPUT=build/client-docs
Use the same client version for generation and assembly. Assembly checks the
catalog pin and generated version metadata, adds reference navigation, and gives
generated pages their titles. It writes a separate source tree; DOCS_SOURCE
must not already exist. Choose another DOCS_SOURCE directory when repeating
assembly and pass it to both tasks.
The completed site starts at build/client-docs/index.html. The Sphinx build
treats warnings as errors, including broken internal links and missing pages.
Prepare a contribution#
Update the implementation and the tests that exercise its changed behavior.
Update the relevant guide or example. Regenerate references after changing commands, flags, or configuration fields.
Run the relevant checks and native build. For VM behavior, record the manual scenario you tried and its result.
Review the diff for generated archives, private VM configurations, and files unrelated to the change.
Open a labeled PR and describe the user-visible result and validation.
For a first end-to-end scenario, follow Getting started. For guest module development, start with Choose and manage modules.