Skip to content

Commit af5212a

Browse files
committed
nix: add dev-shell prefetch script for cloud setup phase
Add build-tools/nix/prefetch-devshell.sh, which realises the `nix develop` shell into /nix/store, plus README-prefetch.md documenting how to wire it into a Claude Code (web) environment setup script. Running the prefetch in the setup-script phase (whose filesystem output is snapshotted and reused) moves the slow first `nix develop` off the interactive session: later sessions find every store path already present and fetch nothing. The script is idempotent, pins a gc-root outside the working tree, and no-ops cleanly when nix is absent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B1ArmS9aNbCxuwhC7zYLBx
1 parent a50b0b2 commit af5212a

2 files changed

Lines changed: 100 additions & 0 deletions

File tree

build-tools/nix/README-prefetch.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Prefetching the Nix dev shell (Claude Code on the web)
2+
3+
`build-tools/nix/prefetch-devshell.sh` realises this project's `nix develop`
4+
shell into the local `/nix/store`. Its purpose is to move the (potentially
5+
slow) first `nix develop` out of the interactive session and into the cloud
6+
environment's **setup-script** phase, whose filesystem output is cached and
7+
reused by every later session.
8+
9+
This complements the `git+https` flake inputs (see the note at the top of
10+
`flake.nix`): the flake change makes resolution *possible* behind the sandbox
11+
proxy; the prefetch makes it *instant* for subsequent sessions.
12+
13+
## Where to put it / how to run it
14+
15+
The script itself lives in the repo (version-controlled and reviewable). You
16+
wire it into the environment via the Claude Code web UI:
17+
18+
1. Open the environment selector (cloud icon) → your environment → **Edit**.
19+
2. In the **Setup script** field, add:
20+
21+
```bash
22+
./build-tools/nix/prefetch-devshell.sh
23+
```
24+
25+
(Keep any existing setup-script lines; just append this one.)
26+
3. Ensure **Network access** is **Trusted** (or a **Custom** list that keeps
27+
the defaults plus `cache.nixos.org`, `cache.iog.io`, and `github.com`).
28+
`None` will make the prefetch fail.
29+
4. Save. The next *new* session rebuilds the environment cache and runs the
30+
prefetch once.
31+
32+
## When it runs
33+
34+
| Trigger | Prefetch runs? |
35+
|---|---|
36+
| First session in the environment | Yes (populates the cache) |
37+
| Later *new* sessions | No — served from the cached snapshot |
38+
| **Resuming** an existing session | No |
39+
| You change the setup script or the allowed-hosts list | Yes (cache rebuilds) |
40+
| Cache expiry (~7 days) | Yes (cache rebuilds) |
41+
42+
Reference: <https://code.claude.com/docs/en/claude-code-on-the-web> (Setup
43+
scripts, Environment caching, Network access).
44+
45+
## Notes
46+
47+
- **Idempotent.** Once the store is warm the script finishes in seconds, so
48+
it is harmless to run repeatedly or by hand on any machine with Nix.
49+
- **gc-root.** It pins the realised shell via a `nix develop --profile`
50+
gc-root at `$HOME/.cache/fls/devshell-profile` (override with
51+
`FLS_DEVSHELL_GCROOT`) so the paths are not garbage-collected before the
52+
session starts. The path is outside the working tree, so `git status` stays
53+
clean.
54+
- **Setup script vs. SessionStart hook.** This is deliberately a *setup
55+
script*, not a `.claude` SessionStart hook: only the setup-script phase is
56+
cached. A SessionStart hook would re-realise the shell on every session
57+
start/resume and add latency for no caching benefit.
58+
- **No `nix`?** The script exits 0 with a message, so it is safe in
59+
environments where Nix is not installed.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Prefetch the Nix dev shell into the local /nix/store.
4+
#
5+
# Intended to run as a Claude Code (web) *setup script* — see
6+
# build-tools/nix/README-prefetch.md. Setup-script output is snapshotted and
7+
# reused by later sessions, so realising the dev shell here means subsequent
8+
# `nix develop` invocations find every path already on disk and perform no
9+
# network fetches at all.
10+
#
11+
# It is also safe to run by hand on any machine: it only populates the store
12+
# and a gc-root, and re-runs are fast once the store is warm.
13+
set -euo pipefail
14+
15+
# Resolve the repo root from this script's location so the setup script can
16+
# invoke it from anywhere.
17+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
18+
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
19+
cd "$REPO_ROOT"
20+
21+
export NIX_CONFIG="experimental-features = nix-command flakes"
22+
23+
if ! command -v nix >/dev/null 2>&1; then
24+
echo "prefetch-devshell: 'nix' not found on PATH; nothing to do." >&2
25+
exit 0
26+
fi
27+
28+
# Keep a gc-root outside the working tree so the realised paths survive a
29+
# garbage collection between setup and the interactive session, and so the
30+
# git tree stays clean.
31+
GCROOT_DIR="${FLS_DEVSHELL_GCROOT:-$HOME/.cache/fls/devshell-profile}"
32+
mkdir -p "$(dirname "$GCROOT_DIR")"
33+
34+
echo "prefetch-devshell: realising dev shell into the store (gc-root: $GCROOT_DIR)"
35+
36+
# `--profile` doubles as a persistent gc-root. `--command true` builds the
37+
# shell environment and exits without dropping into an interactive shell.
38+
nix develop --profile "$GCROOT_DIR" --command true
39+
40+
echo "prefetch-devshell: done. Verifying Agda is available:"
41+
nix develop --profile "$GCROOT_DIR" --command agda --version

0 commit comments

Comments
 (0)