on master help sign in
Make 'nix run' invoke the c manager; expose image copy as .#image
commit443319f68239e71ba29f6f250ae8089bbeb5886d authoriko <mail@iko.soy> dateSat 27 Jun 2026, 20:48 (3 months ago) parent85eaf39
3 files changed+60−70
README.md+42−48 c+1−1 flake.nix+17−21
README.md+42−48
@@ -24,78 +24,72 @@ prompt), and the image ships a handful of dev/LLM tools: `git`, `jujutsu`,
2424
2525[builders]: https://nix.dev/manual/nix/latest/advanced-topics/distributed-builds
2626
27−## Steps
27+## Quick start
2828
29−### 1. Build the image archive
30−
31−`nix run` builds the Linux contents (on your Linux builder) and writes a tagged
32−OCI archive locally via `skopeo`. Pass the output path; the image is tagged
33−`nix-container:latest`.
29+No clone needed — `nix run` drives everything. Run it from a project directory;
30+the container is named after that directory.
3431
3532```sh
36−nix run . -- image.tar.gz
37−```
33+# build the image, load it, and create the container (named after $PWD):
34+nix run github:ilyakooo0/nix-container -- init
3835
39−### 2. Load it into `container`
40−
41−```sh
42−container image load --input image.tar.gz
36+# start it and attach — drops you into fish:
37+nix run github:ilyakooo0/nix-container -- start
4338```
4439
45−### 3. Create and start the container
40+- `init` builds the OCI archive in a temp dir, loads it into `container`,
41+ deletes the temp file, then runs `container create --name <dir> --ssh -it`.
42+- `--ssh` forwards your host SSH agent socket into the container (so `git` over
43+ SSH works with your keys).
44+- Mounts can only be set at creation, so pass them to `init` (forwarded to
45+ `container create`):
4646
47−```sh
48−container create --name nixos --ssh -it nix-container:latest
49−container start -ai nixos
50−```
47+ ```sh
48+ nix run github:ilyakooo0/nix-container -- init -v $PWD:/work
49+ ```
5150
52−- `--ssh` forwards your host SSH agent socket into the container (so `git` over
53− SSH etc. works with your keys).
54−- `-it` / `-ai` give an interactive TTY; `start -ai` attaches to it.
55−
56−You land in `fish`. Exit the shell to stop the container.
57−
58−> **Shortcut:** the [`c`](./c) script bundles the workflow and names the
59−> container after the current directory (handy for per-project containers). It
60−> resolves the flake from its own location, so you can symlink it onto your
61−> `$PATH` and run it from any project:
62−>
63−> ```sh
64−> ./c init # build + load the image, then create the container
65−> ./c init -v $PWD:/work # add create-time mounts (set only at creation)
66−> ./c start # start and attach
67−> ```
68−>
69−> `c init` builds the archive in a temp dir, loads it, and deletes it — so no
70−> `image.tar.gz` is left lying around.
51+Working from a checkout, [`./c init`](./c) / `./c start` are equivalent — and
52+`c` can be symlinked onto your `$PATH` and run from any project.
7153
7254## Re-running after a rebuild
7355
74−`container` keeps the loaded image and the created container, so to pick up a
75−new build, remove the old ones first:
56+`container` keeps the loaded image and the created container, so remove them
57+before re-initialising:
7658
7759```sh
78−nix run . -- image.tar.gz # rebuild the archive
79−container rm nixos # remove the old container (stop it first if running)
60+container rm <dir> # the container is named after the directory
8061container image rm nix-container:latest
81−container image load --input image.tar.gz
82−container create --name nixos --ssh -it nix-container:latest
83−container start -ai nixos
62+nix run github:ilyakooo0/nix-container -- init
63+```
64+
65+## Manual steps
66+
67+`init` is just a wrapper; you can run the pieces yourself for more control. The
68+`image` app is nix2container's skopeo wrapper (`skopeo copy nix:<image> "$@"`) —
69+it takes the ref name from the destination, so spell out the tag:
70+
71+```sh
72+# 1. build a tagged OCI archive
73+nix run github:ilyakooo0/nix-container#image -- oci-archive:image.tar:nix-container:latest
74+
75+# 2. load, create, start
76+container image load --input image.tar
77+container create --name myctr --ssh -it nix-container:latest
78+container start -ai myctr
8479```
8580
8681## Other image destinations
8782
88−`nix run .#copyTo` is nix2container's generic skopeo wrapper
89−(`skopeo copy nix:<image> "$@"`) — the argument is any skopeo destination:
83+The same `image` app can copy anywhere skopeo can:
9084
9185```sh
92−nix run .#copyTo -- docker://ghcr.io/me/nixos:latest # push to a registry
93−nix run .#copyTo -- docker-daemon:nix-container:latest # local Docker daemon
86+nix run github:ilyakooo0/nix-container#image -- docker://ghcr.io/me/img:latest # push to a registry
87+nix run github:ilyakooo0/nix-container#image -- docker-daemon:nix-container:latest # local Docker daemon
9488```
9589
9690## Customize
9791
98−Edit the `buildImage` call in [`flake.nix`](./flake.nix):
92+Fork or clone, then edit the `buildImage` call in [`flake.nix`](./flake.nix):
9993
10094- Add packages to `copyToRoot.paths`.
10195- Change the default process via `config.cmd`.
c+1−1
@@ -11,7 +11,7 @@ switch $argv[1]
1111 case init
1212 # Build the OCI archive into a temp dir, load it, then clean up.
1313 set -l tmp (mktemp -d)
14− nix run $flake -- $tmp/image.tar.gz; and container image load --input $tmp/image.tar.gz
14+ nix run "$flake#image" -- "oci-archive:$tmp/image.tar.gz:nix-container:latest"; and container image load --input $tmp/image.tar.gz
1515 set -l rc $status
1616 rm -rf $tmp
1717 test $rc -eq 0; or exit $rc
flake.nix+17−21
@@ -72,9 +72,7 @@
7272 # Host package set, for the wrapper app below.
7373 pkgsHost = nixpkgs.legacyPackages.${system};
7474
75− # skopeo writes the OCI archive's ref.name from the *destination*
76− # string, not from the image config — so the wrapper app must spell
77− # these out, else the archive loads as `untagged`.
75+ # Name/tag baked into the image's OCI config.
7876 imageName = "nix-container";
7977 imageTag = "latest";
8078
@@ -184,27 +182,25 @@
184182 };
185183 };
186184
187− # `nix run . -- <path>` writes an OCI archive tagged
188− # <imageName>:<imageTag>. The raw `image.copyTo` is a passthrough
189− # (`skopeo copy nix:<image> "$@"`), so an `oci-archive:<path>` with no
190− # ref loads as `untagged`; this bakes the ref into the destination.
191− copyToOCI = pkgsHost.writeShellApplication {
192− name = "copy-to-oci";
193− text = ''
194− out="''${1:-image.tar}"
195− exec ${image.copyTo}/bin/copy-to "oci-archive:$out:${imageName}:${imageTag}"
196− '';
197− };
185+ # `nix run . -- init|start` runs the bundled `c` manager script. Its
186+ # build step shells back to `nix run .#image`; the script finds the
187+ # flake from its own (store) location, so this works from a checkout
188+ # or straight from `nix run github:…/nix-container`.
189+ cApp = pkgsHost.writeShellScriptBin "c" ''
190+ exec ${pkgsHost.fish}/bin/fish ${self}/c "$@"
191+ '';
198192 in
199193 {
200194 apps = {
201− # nix run . -- <path> → OCI archive tagged <name>:<tag>,
202− # loadable with `container image load -i <path>`.
203− default = flake-utils.lib.mkApp { drv = copyToOCI; };
204−
205− # Generic skopeo passthrough for any other destination, e.g.
206− # nix run .#copyTo -- docker://ghcr.io/me/img:latest
207− copyTo = flake-utils.lib.mkApp { drv = image.copyTo; };
195+ # nix run . -- init|start → build+load+create / start a container
196+ default = flake-utils.lib.mkApp { drv = cApp; };
197+
198+ # nix run .#image -- <skopeo-dest> → copy the image anywhere, e.g.
199+ # nix run .#image -- oci-archive:image.tar:nix-container:latest
200+ # nix run .#image -- docker://ghcr.io/me/img:latest
201+ # skopeo (`skopeo copy nix:<image> "$@"`) takes the ref.name from
202+ # the destination, so spell out the tag to avoid an `untagged` load.
203+ image = flake-utils.lib.mkApp { drv = image.copyTo; };
208204 };
209205 }
210206 );