Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8b4af32
feat: add lc launch <target> for sandboxed Claude Code container
aboucaud May 4, 2026
e16dd7a
feat: slim container image, GHCR pull-first, and rebase onto main
aboucaud May 4, 2026
a56862d
revert: restore lc-new Done section to origin/main wording
aboucaud May 4, 2026
6b7700a
fix: address review items 1-7 from lc launch PR
github-actions[bot] May 4, 2026
0c220a4
Improve consistency
aboucaud May 4, 2026
636dd8e
Address item 8
aboucaud May 4, 2026
55924fe
Address item 9
aboucaud May 4, 2026
58ea985
Address item 10
aboucaud May 4, 2026
1d00fec
Address item 11
aboucaud May 4, 2026
7b24fbb
Merge branch 'main' into sandboxing-execution
EiffL May 5, 2026
55a7558
fix(container): pin claude-env base to python:3.12-slim-bookworm
dkn16 May 5, 2026
fac74bd
fix(launcher): drop unsupported --no-setns flag for podman-hpc
dkn16 May 5, 2026
260ad6e
fix(launcher): use --userns=keep-id for rootless podman/podman-hpc
dkn16 May 5, 2026
5a14c28
fix(launcher): drop --userns=keep-id and --dangerously-skip-permissio…
dkn16 May 6, 2026
b0a3a84
fix(launcher): correct GHCR registry ref, suppress warning, project_p…
github-actions[bot] May 6, 2026
1388a7e
feat(launcher): tag launch images as lightcone-<project>:<version> fo…
aboucaud May 6, 2026
5ee7c8b
feat(containers): rename lightcone-sandbox Containerfile; strip propr…
aboucaud May 6, 2026
f62c62f
feat(launcher): decouple harness install — commit-on-first-launch pat…
aboucaud May 6, 2026
6bff004
feat(cli): add --reinstall flag to lc launch
aboucaud May 7, 2026
d15c903
fix(launcher): harden harness install (entrypoint override, OCI tag, …
aboucaud May 8, 2026
e3826af
feat(launcher): rich progress spinners and /lc-new welcome panel
aboucaud May 8, 2026
ef7cd5e
docs: add design spec for harness-decoupling feature
aboucaud May 7, 2026
abe85ca
Merge branch 'main' into sandboxing-execution
aboucaud May 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .github/workflows/container-publish.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Publish Claude container

# Builds and pushes claude-env to ghcr.io on every version tag.
# lc launch claude will pull this image instead of building locally.
on:
push:
tags:
- 'v*.*.*'

jobs:
push:
name: Build and push claude-env
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Extract version from tag
id: version
# Strip the leading 'v' so LIGHTCONE_VERSION matches the PyPI version string.
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"

- name: Build and push
uses: docker/build-push-action@v6
with:
context: claude/lightcone/containers
file: claude/lightcone/containers/claude-env.Containerfile
build-args: |
LIGHTCONE_VERSION=${{ steps.version.outputs.version }}
platforms: linux/amd64,linux/arm64
push: true
tags: |
ghcr.io/lightconeresearch/claude-env:${{ steps.version.outputs.version }}
ghcr.io/lightconeresearch/claude-env:latest
cache-from: type=gha
cache-to: type=gha,mode=max
5 changes: 4 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ astra.yaml ── snakefile generator ──> .lightcone/Snakefile
src/lightcone/ # namespace — NO __init__.py
├── cli/ # Click surface
│ ├── __init__.py # exposes main()
│ ├── commands.py # init, run, status, verify, build

│ ├── commands.py # init, run, status, verify, build, launch, setup
│ ├── plugin.py # get_plugin_source_dir
│ └── claude/ # force-included Claude plugin bundle (in installed wheel only)
├── engine/ # execution substrate — Snakemake-based
Expand Down Expand Up @@ -136,6 +137,8 @@ astra.yaml ── snakefile.generate() ──> .lightcone/Snakefile + .lightcone
- `lc status` — manifest-driven status report
- `lc verify` — chain integrity check
- `lc build` — pre-build container images from Containerfiles
- `lc launch claude` – start Claude Code in a sandbox container for increased safety


Global config (`~/.lightcone/config.yaml`) is auto-created with defaults on first invocation.

Expand Down
55 changes: 55 additions & 0 deletions claude/lightcone/containers/lightcone-sandbox.Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
FROM python:3.12-slim-bookworm

# FUSE support — required by both Apptainer overlay and buildah overlay storage.
# squashfuse enables SquashFS mounts used by Apptainer for OCI images.
# Apptainer — pinned version, installed from the official .deb.
# unzip — required by the OpenCode install script on Linux.
# Note: we pin -bookworm explicitly because plain `python:3.12-slim` flipped to
# Debian 13 (Trixie) where libfuse2 was renamed to libfuse2t64 and would break
# this apt block. Bookworm + libfuse2 is what apptainer 1.4 expects.
ARG APPTAINER_VERSION=1.4.0
RUN apt-get update && apt-get install -y --no-install-recommends \
fuse3 \
libfuse2 \
squashfuse \
buildah \
fakeroot \
git \
curl \
ca-certificates \
build-essential \
unzip \
&& ARCH="$(dpkg --print-architecture)" \
&& if [ "$ARCH" = "amd64" ]; then \
curl -fsSL \
"https://github.com/apptainer/apptainer/releases/download/v${APPTAINER_VERSION}/apptainer_${APPTAINER_VERSION}_amd64.deb" \
-o /tmp/apptainer.deb \
&& apt-get install -y /tmp/apptainer.deb \
&& rm /tmp/apptainer.deb; \
fi \
&& rm -rf /var/lib/apt/lists/*

# uv + lightcone-cli.
# LIGHTCONE_VERSION is substituted at render time (lc launch writes a rendered
# copy to .lightcone/containers/lightcone-sandbox.Containerfile).
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
ENV PATH="/root/.local/bin:$PATH"
ARG LIGHTCONE_VERSION
# Dev/local builds are not published to PyPI; for non-release strings we
# install the latest stable release from PyPI.
RUN case "${LIGHTCONE_VERSION}" in \
*dev*|*+*|dev) uv pip install --system --break-system-packages lightcone-cli ;; \
*) uv pip install --system --break-system-packages "lightcone-cli==${LIGHTCONE_VERSION}" ;; \
esac

# Node.js LTS — required by Claude Code (npm) and OpenCode (npm).
ARG NODE_VERSION=22
RUN curl -fsSL "https://deb.nodesource.com/setup_${NODE_VERSION}.x" | bash - \
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/*

# Marker read by lc build / lc run to detect containerized operation.
ENV LIGHTCONE_CONTAINER=1

WORKDIR /workspace
ENTRYPOINT ["bash"]
18 changes: 16 additions & 2 deletions claude/lightcone/guides/lightcone-cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Reference for lightcone-cli execution: CLI commands, development workflow, statu

```bash
lc init [DIR] [--permissions yolo|recommended|minimal] [--scratch PATH] # Scaffold a new ASTRA project
lc launch <target> # Enter the sandboxed container (lc launch claude)
lc run [OUTPUTS...] [--universe NAME] [--force] [--verbose] [--rerun-triggers TRIGGERS] # Materialize outputs
lc build [--force] [--runtime docker] # Build container images from specs
lc status [--universe NAME] [--json] # Materialization status (text or JSON)
Expand All @@ -20,11 +21,24 @@ The first `lc` invocation auto-creates `~/.lightcone/config.yaml`:

```yaml
container:
runtime: auto # or: docker | podman | podman-hpc | none
runtime: auto # or: docker | podman | podman-hpc | apptainer | singularity | none
```

**Always run via `lc`.** Recipes must execute through `lc run` so that container builds, option resolution, resource limits, and result paths are applied. Treat the underlying execution engine as a black box — never invoke schedulers or container runtimes directly, that will bypass reproducibility guarantees.

## Container Environment

`lc launch claude` is the canonical entry point for all analysis work. After `lc init`, always launch the container before doing anything else:

```bash
lc init my-project && cd my-project
lc launch claude # builds the container on first run (~5 min), then drops into Claude Code
```

Inside the container, `lc build`, `lc run`, `lc status`, and `lc verify` all work normally. Running them outside the container prints a warning — host-side execution is still possible but bypasses the reproducibility sandbox.

The container mounts the project directory at the same absolute path so all output paths, tarball paths, and manifest paths are identical inside and outside.

## Creating Sub-Analyses

Sub-analyses are scaffolded by hand, since each one is just another `astra.yaml` nested in a directory. To add one:
Expand All @@ -37,7 +51,7 @@ Populate the sub-analysis's `astra.yaml` with inputs, outputs, and decisions. Us

## Development Workflow

Three overlapping phases:
All three phases happen **inside the container** (entered via `lc launch claude`):

1. **Write & Debug** — Run scripts directly (`python src/compute.py`) to iterate. Write them recipe-ready from the start: parameterize decisions, write to convention paths, one script per output.
2. **Integrate** — Add `recipe:` blocks to outputs in `astra.yaml`. Track with `lc status` (`alias` / `missing` / `stale` / `ok`). Set `container:` at analysis level or per-recipe — pass an image name (e.g., `python:3.12-slim`) or a path to a Containerfile (e.g., `Containerfile`).
Expand Down
3 changes: 3 additions & 0 deletions claude/lightcone/skills/lc-migrate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@ Whatever approach you use:

## Phase 3: Run & Debug

Enter the container if not already inside it, then materialize:

```bash
lc launch claude # skip if already inside the container
lc run --universe baseline
```

Expand Down
Loading
Loading