@@ -5,44 +5,72 @@ A Nix flake that builds an **OCI image** (via
55Apple's [`container`](https://github.com/apple/container) CLI on macOS.
66
77It's a plain, single-process image — no NixOS, no systemd — defined in
8−[`flake.nix`](./flake.nix). `nix2container` produces a real OCI image directly,
9−so there's no `dockerTools` docker-archive → OCI conversion step.
8+[`flake.nix`](./flake.nix). The default command is `fish` (with a configured
9+prompt), and the image ships a handful of dev/LLM tools: `git`, `jujutsu`,
10+`ripgrep`, `fd`, `jq`, `nodejs`, `python3`, a Rust + C toolchain,
11+`charmbracelet.crush`, `openssh`, and more.
1012
11−- Image contents: **aarch64-linux** (built on your remote Linux builder).
12−- The image is assembled/copied from your **Mac** (aarch64-darwin), so a single
13− `nix run` does the whole thing.
13+## Prerequisites
1414
15−## Build & load into Apple `container`
15+- Apple's `container` CLI installed, with services started:
16+ `container system start` (first run downloads a Linux kernel).
17+- A **Linux builder** — the image *contents* are Linux binaries and can't be
18+ built on macOS. `internal.iko.soy` (aarch64-linux) is already configured, so
19+ `nix` dispatches to it automatically.
20+
21+## Steps
22+
23+### 1. Build the image archive
24+
25+`nix run` builds the Linux contents (on the remote builder) and writes a tagged
26+OCI archive locally via `skopeo`. Pass the output path; the image is tagged
27+`nixos-container:latest`.
1628
1729```sh
18−# Write the image to an OCI archive (runs skopeo locally; builds the
19−# aarch64-linux contents on your remote builder automatically):
20−nix run . -- oci-archive:nixos.tar:nixos-container:latest
21−
22−# Make sure the container services are running (one-time kernel download
23−# on first use), then load and run:
24−container system start
25−container image load -i nixos.tar
26−container run -it nixos-container:latest # default cmd: /bin/bash
27−container run --rm nixos-container:latest /bin/sh -c 'uname -m' # a one-off command
30+nix run . -- image.tar.gz
2831```
2932
30−Note: Apple's `container run` takes the command **directly after the image** —
31−there is no `--` separator (a `--` is parsed as the executable name). The image
32−sets `config.cmd` (not `entrypoint`), so the command you pass *replaces* the
33−default `/bin/bash` instead of being appended to it.
33+### 2. Load it into `container`
34+
35+```sh
36+container image load --input image.tar.gz
37+```
38+
39+### 3. Create and start the container
40+
41+```sh
42+container create --name nixos --ssh -it nixos-container:latest
43+container start -ai nixos
44+```
45+
46+- `--ssh` forwards your host SSH agent socket into the container (so `git` over
47+ SSH etc. works with your keys).
48+- `-it` / `-ai` give an interactive TTY; `start -ai` attaches to it.
49+
50+You land in `fish`. Exit the shell to stop the container.
51+
52+## Re-running after a rebuild
53+
54+`container` keeps the loaded image and the created container, so to pick up a
55+new build, remove the old ones first:
56+
57+```sh
58+nix run . -- image.tar.gz # rebuild the archive
59+container rm nixos # remove the old container (stop it first if running)
60+container image rm nixos-container:latest
61+container image load --input image.tar.gz
62+container create --name nixos --ssh -it nixos-container:latest
63+container start -ai nixos
64+```
3465
35−The default app is nix2container's generic skopeo wrapper
36−(`skopeo copy nix:<image> "$@"`), so the argument is any skopeo destination —
37−here `oci-archive:<path>:<name>:<tag>`.
66+## Other image destinations
3867
39−### Other destinations
68+`nix run .#copyTo` is nix2container's generic skopeo wrapper
69+(`skopeo copy nix:<image> "$@"`) — the argument is any skopeo destination:
4070
4171```sh
42−nix run . -- docker://ghcr.io/me/nixos:latest # push to a registry
43−nix run .#image.copyToDockerDaemon # local Docker
44−nix run .#image.copyToPodman # local Podman
45−nix run .#image.copyToRegistry # registry (uses image name/tag)
72+nix run .#copyTo -- docker://ghcr.io/me/nixos:latest # push to a registry
73+nix run .#copyTo -- docker-daemon:nixos-container:latest # local Docker daemon
4674```
4775
4876## Customize
@@ -50,17 +78,17 @@ nix run .#image.copyToRegistry # registry (uses image name/tag)
5078Edit the `buildImage` call in [`flake.nix`](./flake.nix):
5179
5280- Add packages to `copyToRoot.paths`.
53−- Set the process via `config.entrypoint` / `config.cmd`.
81+- Change the default process via `config.cmd`.
5482- Add env vars via `config.env`.
5583
56−The flake is structured with `flake-utils` over `{aarch64,x86_64}-{darwin,linux}`;
57−the host system maps to the matching Linux target automatically (e.g. an Intel
58−Mac builds an `amd64` image), so there's nothing to change per-arch.
84+The flake uses `flake-utils` over `{aarch64,x86_64}-{darwin,linux}`; the host
85+system maps to the matching Linux target automatically (an Intel Mac builds an
86+`amd64` image), so there's nothing to change per-arch.
5987
60−## Notes
88+## How it works
6189
62−- Building Linux container contents on macOS requires a Linux builder. Yours is
63− already configured (`internal.iko.soy`, aarch64-linux), so `nix run` picks it
64− up automatically.
90+- **Contents** (`copyToRoot`) are built from `pkgsLinux` → the Linux builder.
91+- **Assembly** (`nix2container` + the `skopeo` copy) runs on your Mac, so a
92+ single `nix run` produces a loadable archive.
6593- Apple's `container` runs each container in its own lightweight Linux VM and
6694 consumes standard OCI images — no `--privileged` or systemd needed.