sandcastle: base image on nixos/nix and bake devShells.ci #17

Merged
weiwen merged 3 commits from sandcastle/issue-11 into main 2026-07-05 06:52:31 +08:00
Owner

Summary

Base the sandcastle Docker image on nixos/nix instead of node:22-bookworm and bake devShells.ci from flake.nix into the image at build time.

This eliminates the apt-based tool installation, gives us flake-pinned tool versions, and makes the image reproducible from the same inputs the host uses.

What changed

  • Dockerfile: base image → nixos/nix; install tools via nix develop .#ci which pre-caches every package in /nix/store and symlinks binaries into /usr/local/bin via a new bake-devenv.sh script.
  • flake.nix: new devShells.ci with bash, curl, git, jq, nodejs_22, tea — the tools the agent needs at runtime.
  • Claude Code integration: added ANTHROPIC_API_KEY / CLAUDE_CODE_OAUTH_TOKEN to .env.example; added claude install step in Dockerfile; switched main.mts agents from opencode to claudeCode for plan/implement/review stages.
  • plan-prompt.md: clarified that the issues list has already been filtered to ready-for-agent issues and tightened phrasing.

Reviewer notes

  • Verify that the nix develop .#ci build step works end-to-end in a fresh container.
  • Confirm the bake-devenv.sh approach doesn\t
## Summary Base the sandcastle Docker image on `nixos/nix` instead of `node:22-bookworm` and bake `devShells.ci` from `flake.nix` into the image at build time. This eliminates the apt-based tool installation, gives us flake-pinned tool versions, and makes the image reproducible from the same inputs the host uses. ## What changed - **Dockerfile**: base image → `nixos/nix`; install tools via `nix develop .#ci` which pre-caches every package in `/nix/store` and symlinks binaries into `/usr/local/bin` via a new `bake-devenv.sh` script. - **flake.nix**: new `devShells.ci` with `bash`, `curl`, `git`, `jq`, `nodejs_22`, `tea` — the tools the agent needs at runtime. - **Claude Code integration**: added `ANTHROPIC_API_KEY` / `CLAUDE_CODE_OAUTH_TOKEN` to `.env.example`; added `claude` install step in Dockerfile; switched `main.mts` agents from `opencode` to `claudeCode` for plan/implement/review stages. - **plan-prompt.md**: clarified that the issues list has already been filtered to `ready-for-agent` issues and tightened phrasing. ## Reviewer notes - Verify that the `nix develop .#ci` build step works end-to-end in a fresh container. - Confirm the `bake-devenv.sh` approach doesn\t
Key decisions:
- Added devShells.ci to flake.nix with bash, curl, git, jq, nodejs_22, tea
  (pkgs.tea replaces the previous curl-fetched tea-1.2.0 binary; versions
  are now pinned via the nixpkgs flake input).
- Dockerfile now based on nixos/nix (Alpine) instead of node:22-bookworm.
- devShells.ci is baked during image build via `nix develop .#ci --command bash`
  which pre-populates the nix store; package binaries are symlinked into
  /usr/local/bin so they are on PATH for every exec context (login, non-login,
  sh -c, direct binary call) without relying on profile sourcing.
- User creation switched from glibc groupmod/usermod to Alpine addgroup/adduser
  to match the Alpine-based base image.
- `npm install -g --prefix /usr/local` ensures the opencode binary lands in
  /usr/local/bin rather than the read-only nix store.

Files changed:
- flake.nix — devShells.ci output
- .sandcastle/Dockerfile — nixos/nix base, nix-baked tools, Alpine user setup

Blockers / notes:
- Build has not been exercised end-to-end in this environment (no Docker daemon).
  The `sandbox = false` nix.conf line is required for nix builds inside Docker;
  if builds fail with sandbox errors, verify the Docker daemon has no seccomp
  restrictions that block nix's user namespaces.
- nixos/nix is Alpine-based; if the upstream image ever changes base OS, the
  addgroup/adduser commands in the Dockerfile will need adjustment.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extract nix symlink loop into standalone bake-devenv.sh script using
  COPY heredoc, making the logic readable without Dockerfile escaping
- Fix plan-prompt.md header to accurately describe filtered issue list
  (ready-for-agent, not all open issues)
- Remove redundant filtering explanation since the header is now exact
- Rename 'open issues' to 'candidate issues' for consistency
The Execute phase ran two back-to-back sandbox.run() calls both named
"reviewer" with identical maxIterations, promptFile, and promptArgs,
differing only in model (opencode deepseek vs claude opus). This
executed review-prompt.md twice per branch.

The file's Phase 2 header, the inline Phase 2 comment, and the pr-opener
comment all describe a single reviewer. The second block was a leftover
from switching the reviewer's model in 21952e8, where the new claude
block was added instead of replacing the opencode one and the
surrounding docs were left untouched.

Consolidate to the single Claude Opus reviewer, matching the documented
intent and the per-role model upgrades made in that commit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
weiwen force-pushed sandcastle/issue-11 from 7c00024e2e to 5ca201198a
Some checks failed
CI / check (pull_request) Has been cancelled
2026-07-05 06:52:22 +08:00
Compare
weiwen merged commit c8e0952763 into main 2026-07-05 06:52:31 +08:00
weiwen deleted branch sandcastle/issue-11 2026-07-05 06:52:31 +08:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
weiwen/evie!17
No description provided.