Skip to content

Modular sandbox: all languages depend on essentials, full sandbox assembles via COPY --from#38

Merged
konard merged 13 commits intomainfrom
issue-37-06e880b28d2a
Feb 1, 2026
Merged

Modular sandbox: all languages depend on essentials, full sandbox assembles via COPY --from#38
konard merged 13 commits intomainfrom
issue-37-06e880b28d2a

Conversation

@konard
Copy link
Member

@konard konard commented Feb 1, 2026

Summary

Implements the modular sandbox architecture requested in #37. All language Docker images now depend on konard/sandbox-essentials, and the full sandbox (konard/sandbox) assembles all language runtimes via multi-stage COPY --from.

Architecture

ubuntu:24.04
  └─ sandbox-js (Node.js, Bun, Deno)
       └─ sandbox-essentials (git, gh, glab, dev libraries)
            ├─ sandbox-python   ──┐
            ├─ sandbox-go        │
            ├─ sandbox-rust      │
            ├─ sandbox-java      │
            ├─ sandbox-kotlin    │  All build in parallel
            ├─ sandbox-ruby      │
            ├─ sandbox-php       │
            ├─ sandbox-perl      │
            ├─ sandbox-swift     │
            ├─ sandbox-lean      │
            ├─ sandbox-rocq     ──┘
            └─ sandbox (full) ← COPY --from all language images

Key Changes

Area Change
Language Dockerfiles (15 files) Changed FROM ubuntu:24.04FROM konard/sandbox-essentials:latest
Language install.sh (14 files) Added /tmp/common.sh fallback for Docker build context; removed duplicate apt installs
Full sandbox Dockerfiles (root + full-sandbox) Multi-stage COPY --from assembly from 11 language image stages
CI/CD workflow Matrix-based parallel language builds; full sandbox waits for all
PR test build Builds complete chain: JS → essentials → 11 languages → full sandbox
Documentation Updated README.md and ARCHITECTURE.md

How Full Sandbox Assembly Works

  1. Each language image installs its runtime to $HOME/.<tool> (e.g., .pyenv, .cargo, .go)
  2. Full sandbox declares all 11 language images as build stages
  3. COPY --from=<lang>-stage copies each runtime directory
  4. System-level packages (dotnet, R, C/C++, assembly) are installed via apt
  5. .bashrc files from all stages are merged (unique lines appended)

CI/CD Pipeline

  • PR builds: Sequential build of full chain on a single runner for testing
  • Release builds: Languages build in parallel across matrix (amd64 + arm64), full sandbox waits for all language manifests before assembly

Test Plan

  • CI docker-build-test passes - builds all 11 language images + full sandbox
  • JS sandbox test passes (node --version, bun --version, deno --version)
  • Essentials sandbox test passes (git --version, gh --version)
  • Full sandbox test passes (all language runtimes accessible)
  • Release build deploys all images correctly (after merge)

Fixes #37


🤖 Generated with Claude Code

Adding CLAUDE.md with task information for AI processing.
This file will be removed when the task is complete.

Issue: #37
@konard konard self-assigned this Feb 1, 2026
konard and others added 2 commits February 1, 2026 17:44
Split the monolithic sandbox into modular components:

- ubuntu/24.04/common.sh: Shared functions and utilities
- ubuntu/24.04/<language>/install.sh: Per-language install scripts
- ubuntu/24.04/<language>/Dockerfile: Per-language Docker images
- ubuntu/24.04/essentials-sandbox/: Minimal image with git identity tools
- ubuntu/24.04/full-sandbox/: Complete image with all languages

Languages supported as individual modules:
js, python, go, rust, java, kotlin, dotnet, r, ruby, php, perl, swift,
lean, rocq, cpp, assembly

The root Dockerfile remains backward-compatible and continues to build
the full sandbox image using the existing install script.

CI/CD workflow updated to detect changes in ubuntu/ directory.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update all 16 language Dockerfiles to use repo-root-relative COPY paths
so they can be built with `docker build -f ubuntu/24.04/<lang>/Dockerfile .`
from the repository root. Also add common.sh COPY and remove the invalid
COPY --from=entrypoint in js/Dockerfile.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@konard konard changed the title [WIP] Let's split our big sandbox in multiple small sandboxes Fix per-language Dockerfiles to build from repo root Feb 1, 2026
- Update README.md with modular architecture table and usage examples
- Update ARCHITECTURE.md with new file structure and modular design diagram
- Fix essentials-sandbox and full-sandbox Dockerfiles to use repo root
  build context (docker build -f <path>/Dockerfile .)
- Add changeset for minor version bump

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@konard konard changed the title Fix per-language Dockerfiles to build from repo root Split sandbox into modular per-language components Feb 1, 2026
@konard konard marked this pull request as ready for review February 1, 2026 16:50
@konard
Copy link
Member Author

konard commented Feb 1, 2026

🤖 Solution Draft Log

This log file contains the complete execution trace of the AI solution draft process.

💰 Cost estimation:

  • Public pricing estimate: $9.462754 USD
  • Calculated by Anthropic: $6.686004 USD
  • Difference: $-2.776750 (-29.34%)
    📎 Log file uploaded as Gist (1337KB)
    🔗 View complete solution draft log

Now working session is ended, feel free to review and add any feedback on the solution draft.

@konard
Copy link
Member Author

konard commented Feb 1, 2026

Double check we only rebuild images, for which scripts or dockerfiles are changes, otherwise for the full sandbox we reuse latest versions of essentials and language specific sandboxes. Also make sure we have separate JavaScript version of sandbox, that essentials builds up on. So if we really want to, we can have JavaScript sandbox without any essentials also separately. So we should focus on efficiency of CI/CD flow. All language specific sandboxes should be built in parallel, and once required sandboxes builded, we can build essentials and full (after all including essentials is done).

Ensure all changes are correct, consistent and fully meet all discussed requirements (check issue description and all comments in issue and in pull request).

@konard konard marked this pull request as draft February 1, 2026 18:38
@konard
Copy link
Member Author

konard commented Feb 1, 2026

🤖 AI Work Session Started

Starting automated work session at 2026-02-01T18:38:47.470Z

The PR has been converted to draft mode while work is in progress.

This comment marks the beginning of an AI work session. Please wait working session to finish, and provide your feedback.

konard and others added 2 commits February 1, 2026 19:46
Refactor the modular sandbox to use a proper layered Docker image
hierarchy where each layer builds on top of the previous:

- JS sandbox (konard/sandbox-js): standalone Node.js, Bun, Deno
- Essentials sandbox (konard/sandbox-essentials): builds on JS,
  adds git, gh, glab, gh-setup-git-identity, glab-setup-git-identity
- Full sandbox (konard/sandbox): builds on essentials, adds all
  remaining languages

CI/CD workflow updated with per-image change detection:
- Only rebuild images whose scripts/Dockerfiles actually changed
- Reuse latest published images for unchanged base layers
- JS sandbox amd64/arm64 built in parallel
- Essentials waits for JS, then builds in parallel per arch
- Full sandbox waits for essentials, then builds per arch
- Each image gets its own multi-arch manifest

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Root Dockerfile now builds on top of essentials-sandbox image using
the full-sandbox/install.sh script, matching the layered architecture
(JS → essentials → full). Removes dependency on legacy
ubuntu-24-server-install.sh script.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@konard konard changed the title Split sandbox into modular per-language components Split sandbox into layered modular images: JS → essentials → full Feb 1, 2026
The docker-build-test job now builds the full chain locally:
JS → essentials → full sandbox, since the base images may not
exist on registries yet during PR testing.

Also adds separate test steps for JS and essentials sandboxes
to verify each layer independently.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@konard konard marked this pull request as ready for review February 1, 2026 18:56
@konard
Copy link
Member Author

konard commented Feb 1, 2026

Changes Made

Addressed the feedback to create a layered Docker image architecture with efficient CI/CD:

Architecture: JS → Essentials → Full

konard/sandbox-js (standalone)
  └─ Node.js, Bun, Deno, npm
      ↓
konard/sandbox-essentials (built on JS)
  └─ + git, gh, glab, gh-setup-git-identity, glab-setup-git-identity
      ↓
konard/sandbox (built on essentials)
  └─ + Python, Go, Rust, Java, Kotlin, .NET, R, Ruby, PHP, Perl, Swift, Lean, Rocq, C/C++, Assembly

Key Changes

  1. JS sandbox is separate and standalone - can be used without essentials overhead
  2. Essentials builds ON TOP of JS - uses FROM ${JS_IMAGE} with build arg
  3. Full sandbox builds ON TOP of essentials - uses FROM ${ESSENTIALS_IMAGE} with build arg
  4. Root Dockerfile updated - no longer uses legacy ubuntu-24-server-install.sh, now uses the modular full-sandbox/install.sh
  5. Per-image change detection - only rebuild images whose scripts/Dockerfiles changed
  6. Layered CI/CD pipeline - JS builds first (amd64/arm64 parallel), then essentials, then full
  7. Image reuse - unchanged base layers use latest published images (e.g., if only full-sandbox changed, JS and essentials are reused from registry)

Files Modified

  • Dockerfile - builds on essentials image
  • ubuntu/24.04/js/Dockerfile - standalone JS image
  • ubuntu/24.04/essentials-sandbox/Dockerfile - builds on JS
  • ubuntu/24.04/essentials-sandbox/install.sh - only adds git identity tools (no JS duplication)
  • ubuntu/24.04/full-sandbox/Dockerfile - builds on essentials
  • ubuntu/24.04/full-sandbox/install.sh - only adds remaining languages
  • .github/workflows/release.yml - per-image change detection + layered builds
  • README.md + ARCHITECTURE.md - updated diagrams and descriptions

@konard
Copy link
Member Author

konard commented Feb 1, 2026

🤖 Solution Draft Log

This log file contains the complete execution trace of the AI solution draft process.

💰 Cost estimation:

  • Public pricing estimate: $7.978089 USD
  • Calculated by Anthropic: $5.444686 USD
  • Difference: $-2.533403 (-31.75%)
    📎 Log file uploaded as Gist (1148KB)
    🔗 View complete solution draft log

Now working session is ended, feel free to review and add any feedback on the solution draft.

@konard
Copy link
Member Author

konard commented Feb 1, 2026

We have lot's of duplicate dependencies like curl git sudo ca-certificates build-essentials and so on, and also full sandbox should be build on top of all languages.

As most of language version are using lot's of duplicate packages installed in apt-get, we should put all duplicates in our sandbox-essentials, so there will be no conflicts between different versions.

So full sandbox will merge files from all languages nicely. And most or all language versions will depend on sandbox-essentials, and also it will be available as sandbox-js alias without modification.

And ensure all tests pass.

@konard konard marked this pull request as draft February 1, 2026 20:00
@konard
Copy link
Member Author

konard commented Feb 1, 2026

🤖 AI Work Session Started

Starting automated work session at 2026-02-01T20:00:00.616Z

The PR has been converted to draft mode while work is in progress.

This comment marks the beginning of an AI work session. Please wait working session to finish, and provide your feedback.

- Add unzip to JS Dockerfile (required by Bun installer)
- Move common dev libraries (libssl-dev, zlib1g-dev, libyaml-dev, etc.)
  from full-sandbox to essentials-sandbox to avoid duplication
- Remove gh/glab-setup-git-identity from JS install.sh (belongs in
  essentials only, JS should be standalone without essentials overhead)
- Move bubblewrap install from user-level heredoc to system-level in
  full-sandbox

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@konard konard marked this pull request as ready for review February 1, 2026 20:30
@konard
Copy link
Member Author

konard commented Feb 1, 2026

Changes Made

Addressed feedback to deduplicate dependencies and fix the CI failure:

Fixes

  1. CI fix: Added unzip to JS Dockerfile — Bun installer requires it
  2. JS sandbox is now standalone: Removed gh-setup-git-identity and glab-setup-git-identity from js/install.sh (they belong in essentials only)
  3. Deduplicated dependencies: Moved common dev libraries (libssl-dev, zlib1g-dev, libyaml-dev, etc.) from full-sandbox/install.sh to essentials-sandbox/install.sh
  4. Moved bubblewrap install from user-level heredoc to system-level in full-sandbox/install.sh

Architecture

konard/sandbox-js (standalone)
  └─ Node.js, Bun, Deno, npm (no identity tools)
      ↓
konard/sandbox-essentials (built on JS)
  └─ + common dev libs + git, gh, glab, identity tools
      ↓
konard/sandbox (built on essentials)
  └─ + all remaining languages (no duplicate deps)

CI Status

All checks pass ✅ (docker-build-test builds all 3 layers and tests them)

@konard
Copy link
Member Author

konard commented Feb 1, 2026

🤖 Solution Draft Log

This log file contains the complete execution trace of the AI solution draft process.

💰 Cost estimation:

  • Public pricing estimate: $5.659810 USD
  • Calculated by Anthropic: $3.296532 USD
  • Difference: $-2.363277 (-41.76%)
    📎 Log file uploaded as Gist (653KB)
    🔗 View complete solution draft log

Now working session is ended, feel free to review and add any feedback on the solution draft.

@konard
Copy link
Member Author

konard commented Feb 1, 2026

You didn't understand me correctly.

JS language and all other languages now should depend on sandbox-essentials, meaning each Dockerfile of language depends on konard/sandbox-essentials, and sh files also depend on konard/sandbox-essentials' sh file.

So sh files depend on sh files, docker files depend on other docker images.

And for konard/sandbox (full sandbox) I want to be able to copy/merge files from all others languages images + konard/sandbox-essentials image.

And we also be specific with all versions we install of all software, so they don't conflicts on files copy/merging.

So konard/sandbox should depend on almost all others docker images, that is why it will wait for them to finish building to be assembled.

@konard konard marked this pull request as draft February 1, 2026 20:51
@konard
Copy link
Member Author

konard commented Feb 1, 2026

🤖 AI Work Session Started

Starting automated work session at 2026-02-01T20:51:08.547Z

The PR has been converted to draft mode while work is in progress.

This comment marks the beginning of an AI work session. Please wait working session to finish, and provide your feedback.

konard and others added 4 commits February 1, 2026 22:06
…-from

Redesign architecture so every language image builds on top of
konard/sandbox-essentials (not ubuntu:24.04), and the full sandbox
(konard/sandbox) merges all language images via multi-stage COPY --from.

Key changes:
- All 15 language Dockerfiles now use FROM konard/sandbox-essentials
- Language install.sh scripts no longer install duplicate system deps
- Full sandbox Dockerfile uses COPY --from for 11 user-home languages
  (python, go, rust, java, kotlin, ruby, php, perl, swift, lean, rocq)
- System packages (.NET, R, C/C++, Assembly) still installed via apt
- CI/CD uses matrix strategy for parallel language builds (amd64+arm64)
- Full sandbox waits for all language images before assembly
- bashrc configs merged from all language stages
- README and ARCHITECTURE updated with new diagrams

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add --chown=sandbox:sandbox to COPY directives in all language
Dockerfiles that run as USER sandbox. The essentials base image
ends with USER sandbox, so COPY creates root-owned files that
the sandbox user cannot chmod.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move ESSENTIALS_IMAGE ARG declaration before all FROM statements
in both root Dockerfile and full-sandbox Dockerfile. Docker ARGs
declared after FROM are stage-scoped and lose their values for
subsequent stages, causing "base name should not be blank" errors.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The opam install script was receiving "y" as installation path instead
of accepting the default. Fix by providing the correct path
($HOME/.local/bin) as first input. Also add fallback direct binary
download and ensure .opam directory always exists for COPY --from.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@konard konard changed the title Split sandbox into layered modular images: JS → essentials → full Modular sandbox: all languages depend on essentials, full sandbox assembles via COPY --from Feb 1, 2026
@konard konard marked this pull request as ready for review February 1, 2026 22:25
@konard
Copy link
Member Author

konard commented Feb 1, 2026

🤖 Solution Draft Log

This log file contains the complete execution trace of the AI solution draft process.

💰 Cost estimation:

  • Public pricing estimate: $13.429840 USD
  • Calculated by Anthropic: $10.050815 USD
  • Difference: $-3.379025 (-25.16%)
    📎 Log file uploaded as Gist (2080KB)
    🔗 View complete solution draft log

Now working session is ended, feel free to review and add any feedback on the solution draft.

@konard konard merged commit 41e3155 into main Feb 1, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Let's split our big sandbox in multiple small sandboxes

1 participant