Skip to content

build(docker): lucebox-hub container image + CI release pipeline#334

Open
easel wants to merge 4 commits into
Luce-Org:mainfrom
easel:feat/docker-stack
Open

build(docker): lucebox-hub container image + CI release pipeline#334
easel wants to merge 4 commits into
Luce-Org:mainfrom
easel:feat/docker-stack

Conversation

@easel
Copy link
Copy Markdown
Collaborator

@easel easel commented Jun 3, 2026

Summary

Containerization and CI plumbing for lucebox-hub. Adds a Dockerfile + docker-bake.hcl + scripts/build_image.sh that build the image, an entrypoint that emits IMAGE_INFO / HOST_INFO sidecars consumed by /props schema-3/4, and GitHub Actions for image build (docker.yml), CI integration, and luce-bench release tagging. Also ships workspace-root files the build needs (pyproject.toml, uv.lock, Makefile, .gitignore, README, .dockerignore).

This PR is the foundational docker stack — siblings #335 (lucebox-cli) and #337 (luce-bench) layer their Python surfaces on top. To keep CI green on this branch alone, the root pyproject.toml workspace members list, Dockerfile COPY directives, and Makefile test target intentionally exclude lucebox/, luce-bench/, and harness/ — those re-appear in their respective sibling diffs.

Files

  • Build/runtime: Dockerfile, docker-bake.hcl, scripts/build_image.sh, server/scripts/entrypoint.sh, .dockerignore
  • CI: .github/workflows/docker.yml, .github/workflows/release-luce-bench.yml, .github/workflows/ci.yml
  • Workspace root: pyproject.toml, uv.lock, Makefile, .gitignore, README.md

Dependencies

  • feat(lucebox): hub CLI + autotune/sweep/profile + harness adapters + shell wrapper #335 (lucebox-cli) — re-adds lucebox to the workspace members list, re-introduces the COPY ./lucebox /src/lucebox (and runtime stage copy) into the Dockerfile, restores the lucebox/**/*.py ruff include, and wires the lucebox/tests path back into make test. The lucebox CLI subcommand routing in server/scripts/entrypoint.sh is already in place; it just won't resolve until the package lands.
  • feat(luce-bench): in-tree bench harness + multi-turn agent_recorded + LLM judge #337 (luce-bench) — re-adds luce-bench to workspace members, re-introduces the COPY ./luce-bench /src/luce-bench (and runtime stage copy) into the Dockerfile, restores the luce-bench/tests path in make test, and unblocks the release-luce-bench.yml tag-push workflow (currently shipped but won't fire until the luce-bench/ source tree exists).

This PR builds green on its own. Once #335 and #337 land they each add their own slice of workspace members, Dockerfile COPYs, and Makefile entries.

Test plan

@easel easel force-pushed the feat/docker-stack branch from 06d1366 to 5627861 Compare June 4, 2026 02:27
@easel easel force-pushed the feat/docker-stack branch from 5627861 to cf05060 Compare June 4, 2026 04:48
easel added a commit to easel/lucebox-hub that referenced this pull request Jun 4, 2026
Moved from PR Luce-Org#334 (docker-stack) where it was flagged as out-of-scope.
luce-bench/tests/test_extract_agentic_fixture.py loads this script via
path, so it belongs in the same PR as the tests.
@easel easel force-pushed the feat/docker-stack branch 2 times, most recently from dcf3597 to f3bda05 Compare June 4, 2026 05:02
easel added a commit to easel/lucebox-hub that referenced this pull request Jun 4, 2026
… adapters

## What

New lucebox/ Python package exposing the hub CLI (autotune, sweep,
profile, smoke, models, config, download, host-check, docker_run) plus
the lucebox.sh launcher wrapper and install.sh. Adds the harness/
adapter package wrapping external coding agents (claude_code, codex,
hermes, openclaw, opencode, pi) that autotune sweeps drive. Ships
scripts/check_lucebox_wrapper_sandbox.sh and scripts/test_lucebox_sh.sh
for wrapper validation, full pytest coverage under lucebox/tests/, and
the bragi autotune profile-sweep protocol docs.

## Why

This is the user-facing surface of lucebox-hub: one CLI to launch the
image, tune layer-split / pflash settings against a host, run sweeps,
and dispatch bench runs. Splitting it out keeps Python-side review
independent of the C++ server and Docker stack reviews.

## Dependencies

- Luce-Org#334 (docker-stack): docker_run.py launches the lucebox-hub image
- Luce-Org#337 (lucebench-harness): lucebox bench delegates to luce-bench (workspace dep)
- Luce-Org#336 (server-layer-split): autotune presumes layer-split build artifacts
@easel easel force-pushed the feat/docker-stack branch from f3bda05 to b203876 Compare June 4, 2026 17:15
easel added a commit to easel/lucebox-hub that referenced this pull request Jun 4, 2026
… adapters

## What

New lucebox/ Python package exposing the hub CLI (autotune, sweep,
profile, smoke, models, config, download, host-check, docker_run) plus
the lucebox.sh launcher wrapper and install.sh. Adds the harness/
adapter package wrapping external coding agents (claude_code, codex,
hermes, openclaw, opencode, pi) that autotune sweeps drive. Ships
scripts/check_lucebox_wrapper_sandbox.sh and scripts/test_lucebox_sh.sh
for wrapper validation, full pytest coverage under lucebox/tests/, and
the bragi autotune profile-sweep protocol docs.

## Why

This is the user-facing surface of lucebox-hub: one CLI to launch the
image, tune layer-split / pflash settings against a host, run sweeps,
and dispatch bench runs. Splitting it out keeps Python-side review
independent of the C++ server and Docker stack reviews.

## Dependencies

- Luce-Org#334 (docker-stack): docker_run.py launches the lucebox-hub image
- Luce-Org#337 (lucebench-harness): lucebox bench delegates to luce-bench (workspace dep)
- Luce-Org#336 (server-layer-split): autotune presumes layer-split build artifacts
easel added a commit to easel/lucebox-hub that referenced this pull request Jun 4, 2026
… adapters

## What

New lucebox/ Python package exposing the hub CLI (autotune, sweep,
profile, smoke, models, config, download, host-check, docker_run) plus
the lucebox.sh launcher wrapper and install.sh. Adds the harness/
adapter package wrapping external coding agents (claude_code, codex,
hermes, openclaw, opencode, pi) that autotune sweeps drive. Ships
scripts/check_lucebox_wrapper_sandbox.sh and scripts/test_lucebox_sh.sh
for wrapper validation, full pytest coverage under lucebox/tests/, and
the bragi autotune profile-sweep protocol docs.

## Why

This is the user-facing surface of lucebox-hub: one CLI to launch the
image, tune layer-split / pflash settings against a host, run sweeps,
and dispatch bench runs. Splitting it out keeps Python-side review
independent of the C++ server and Docker stack reviews.

## Dependencies

- Luce-Org#334 (docker-stack): docker_run.py launches the lucebox-hub image
- Luce-Org#337 (lucebench-harness): lucebox bench delegates to luce-bench (workspace dep)
- Luce-Org#336 (server-layer-split): autotune presumes layer-split build artifacts
## What

Containerization stack for lucebox-hub. Dockerfile + docker-bake.hcl
build the lucebox-hub image (build-env and runtime stages);
scripts/build_image.sh drives local builds; server/scripts/entrypoint.sh
emits IMAGE_INFO / HOST_INFO sidecars consumed by /props. GitHub Actions
add .github/workflows/docker.yml (build & publish), update ci.yml, and
add release-luce-bench.yml for tagging. Workspace-root files
(pyproject.toml, uv.lock, Makefile, lefthook.yml, .gitignore, README)
live here because the Dockerfile uv-syncs the workspace at build time.

## Why

Provides the reproducible image and CI pipeline every other split PR
deploys into. Centralizing build/publish here keeps Dockerfile,
entrypoint, and workspace-root pinning in one reviewable change.

## Dependencies

- Luce-Org#335 (lucebox-cli): Dockerfile COPYs lucebox/ into the image
- Luce-Org#337 (lucebench-harness): Dockerfile COPYs luce-bench/ into the image
@easel easel force-pushed the feat/docker-stack branch from b203876 to 08f079f Compare June 4, 2026 17:19
easel added a commit to easel/lucebox-hub that referenced this pull request Jun 4, 2026
… adapters

## What

New lucebox/ Python package exposing the hub CLI (autotune, sweep,
profile, smoke, models, config, download, host-check, docker_run) plus
the lucebox.sh launcher wrapper and install.sh. Adds the harness/
adapter package wrapping external coding agents (claude_code, codex,
hermes, openclaw, opencode, pi) that autotune sweeps drive. Ships
scripts/check_lucebox_wrapper_sandbox.sh and scripts/test_lucebox_sh.sh
for wrapper validation, full pytest coverage under lucebox/tests/, and
the bragi autotune profile-sweep protocol docs.

## Why

This is the user-facing surface of lucebox-hub: one CLI to launch the
image, tune layer-split / pflash settings against a host, run sweeps,
and dispatch bench runs. Splitting it out keeps Python-side review
independent of the C++ server and Docker stack reviews.

## Dependencies

- Luce-Org#334 (docker-stack): docker_run.py launches the lucebox-hub image
- Luce-Org#337 (lucebench-harness): lucebox bench delegates to luce-bench (workspace dep)
- Luce-Org#336 (server-layer-split): autotune presumes layer-split build artifacts
@easel easel force-pushed the feat/docker-stack branch from 34d96a7 to 1ab4599 Compare June 4, 2026 18:37
easel added a commit to easel/lucebox-hub that referenced this pull request Jun 4, 2026
… adapters

## What

New lucebox/ Python package exposing the hub CLI (autotune, sweep,
profile, smoke, models, config, download, host-check, docker_run) plus
the lucebox.sh launcher wrapper and install.sh. Adds the harness/
adapter package wrapping external coding agents (claude_code, codex,
hermes, openclaw, opencode, pi) that autotune sweeps drive. Ships
scripts/check_lucebox_wrapper_sandbox.sh and scripts/test_lucebox_sh.sh
for wrapper validation, full pytest coverage under lucebox/tests/, and
the bragi autotune profile-sweep protocol docs.

## Why

This is the user-facing surface of lucebox-hub: one CLI to launch the
image, tune layer-split / pflash settings against a host, run sweeps,
and dispatch bench runs. Splitting it out keeps Python-side review
independent of the C++ server and Docker stack reviews.

## Dependencies

- Luce-Org#334 (docker-stack): docker_run.py launches the lucebox-hub image
- Luce-Org#337 (lucebench-harness): lucebox bench delegates to luce-bench (workspace dep)
- Luce-Org#336 (server-layer-split): autotune presumes layer-split build artifacts
@easel easel marked this pull request as ready for review June 4, 2026 23:18
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 13 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread Makefile Outdated
Comment thread server/scripts/entrypoint.sh Outdated
Comment thread .github/workflows/docker.yml
Comment thread server/scripts/entrypoint.sh Outdated
Comment thread server/scripts/entrypoint.sh
easel added a commit to easel/lucebox-hub that referenced this pull request Jun 4, 2026
… adapters

## What

New lucebox/ Python package exposing the hub CLI (autotune, sweep,
profile, smoke, models, config, download, host-check, docker_run) plus
the lucebox.sh launcher wrapper and install.sh. Adds the harness/
adapter package wrapping external coding agents (claude_code, codex,
hermes, openclaw, opencode, pi) that autotune sweeps drive. Ships
scripts/check_lucebox_wrapper_sandbox.sh and scripts/test_lucebox_sh.sh
for wrapper validation, full pytest coverage under lucebox/tests/, and
the bragi autotune profile-sweep protocol docs.

## Why

This is the user-facing surface of lucebox-hub: one CLI to launch the
image, tune layer-split / pflash settings against a host, run sweeps,
and dispatch bench runs. Splitting it out keeps Python-side review
independent of the C++ server and Docker stack reviews.

## Dependencies

- Luce-Org#334 (docker-stack): docker_run.py launches the lucebox-hub image
- Luce-Org#337 (lucebench-harness): lucebox bench delegates to luce-bench (workspace dep)
- Luce-Org#336 (server-layer-split): autotune presumes layer-split build artifacts
easel added a commit to easel/lucebox-hub that referenced this pull request Jun 5, 2026
… adapters

## What

New lucebox/ Python package exposing the hub CLI (autotune, sweep,
profile, smoke, models, config, download, host-check, docker_run) plus
the lucebox.sh launcher wrapper and install.sh. Adds the harness/
adapter package wrapping external coding agents (claude_code, codex,
hermes, openclaw, opencode, pi) that autotune sweeps drive. Ships
scripts/check_lucebox_wrapper_sandbox.sh and scripts/test_lucebox_sh.sh
for wrapper validation, full pytest coverage under lucebox/tests/, and
the bragi autotune profile-sweep protocol docs.

## Why

This is the user-facing surface of lucebox-hub: one CLI to launch the
image, tune layer-split / pflash settings against a host, run sweeps,
and dispatch bench runs. Splitting it out keeps Python-side review
independent of the C++ server and Docker stack reviews.

## Dependencies

- Luce-Org#334 (docker-stack): docker_run.py launches the lucebox-hub image
- Luce-Org#337 (lucebench-harness): lucebox bench delegates to luce-bench (workspace dep)
- Luce-Org#336 (server-layer-split): autotune presumes layer-split build artifacts
easel added 2 commits June 5, 2026 16:02
- Makefile clean-models: validate MODELS_DIR before rm -rf; reject /,
  empty, $HOME, and top-level system dirs to prevent catastrophic
  deletion when overriding the variable.
- entrypoint.sh _emit_gpu_array: split nvidia-smi CSV on `,` (with
  per-field whitespace trim) rather than the literal `, ` two-char
  separator, so drivers that emit bare comma delimiters still parse
  GPU metadata correctly into /props.host.
- entrypoint.sh draft auto-resolution: sort find matches lexicographi-
  cally before head -1 so the picked draft is deterministic across
  filesystems (find traversal order alone is FS-dependent).
- entrypoint.sh multi-target: refuse to auto-select when multiple
  target GGUFs are present in models/. Die with the candidate list so
  the operator must pick via DFLASH_TARGET — silently picking the
  alphabetical first has burned us on bench runs before.
- docker.yml: add `on: push: branches: [main]` and include push-on-main
  in the bake-action push condition so main merges actually publish
  the rolling `:cuda12` tag (the metadata `enable=` rule already
  expected it).
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="server/scripts/entrypoint.sh">

<violation number="1" location="server/scripts/entrypoint.sh:446">
P2: Draft autodetection can abort under `set -euo pipefail` because `sort | head -n 1` may fail with SIGPIPE when multiple matches exist.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

# Sort matches lexicographically so the pick is deterministic across
# filesystems (find's traversal order is filesystem-dependent without
# an explicit sort). First lexicographic match wins.
DRAFT_FILE="$(find -L "$DFLASH_DRAFT" -maxdepth 4 -type f -iname "$pattern" -print 2>/dev/null | sort | head -n 1)"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Draft autodetection can abort under set -euo pipefail because sort | head -n 1 may fail with SIGPIPE when multiple matches exist.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/scripts/entrypoint.sh, line 446:

<comment>Draft autodetection can abort under `set -euo pipefail` because `sort | head -n 1` may fail with SIGPIPE when multiple matches exist.</comment>

<file context>
@@ -436,7 +440,10 @@ if [ -d "$DFLASH_DRAFT" ]; then
+        # Sort matches lexicographically so the pick is deterministic across
+        # filesystems (find's traversal order is filesystem-dependent without
+        # an explicit sort). First lexicographic match wins.
+        DRAFT_FILE="$(find -L "$DFLASH_DRAFT" -maxdepth 4 -type f -iname "$pattern" -print 2>/dev/null | sort | head -n 1)"
         if [ -n "$DRAFT_FILE" ]; then
             # Mark the family-specific match so the log line below can
</file context>
Suggested change
DRAFT_FILE="$(find -L "$DFLASH_DRAFT" -maxdepth 4 -type f -iname "$pattern" -print 2>/dev/null | sort | head -n 1)"
DRAFT_FILE="$(find -L "$DFLASH_DRAFT" -maxdepth 4 -type f -iname "$pattern" -print 2>/dev/null | sort | sed -n '1p')"

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.

1 participant