Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Build and publish nvim-dev container image
# Triggered on changes to dot_files/nvim/ or manual dispatch
# Image published to: ghcr.io/binarypie-dev/nvim-dev:latest
# Build and publish the devcube container image
# Triggered on changes to the baked dot_files configs or manual dispatch
# Image published to: ghcr.io/binarypie-dev/devcube:latest

name: Build nvim-dev Image
name: Build devcube Image

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand All @@ -13,20 +13,30 @@ on:
branches:
- main
paths:
# Config is baked into the image, so any config change must rebuild.
# Configs are baked into the image, so any config change must rebuild.
- 'dot_files/devcube/**'
- 'dot_files/nvim/**'
- '.github/workflows/build-nvim-dev.yml'
- 'dot_files/fish/**'
- 'dot_files/starship/**'
- 'dot_files/zellij/**'
- 'dot_files/workmux/**'
- '.github/workflows/build-devcube.yml'
pull_request:
paths:
- 'dot_files/devcube/**'
- 'dot_files/nvim/**'
- '.github/workflows/build-nvim-dev.yml'
- 'dot_files/fish/**'
- 'dot_files/starship/**'
- 'dot_files/zellij/**'
- 'dot_files/workmux/**'
- '.github/workflows/build-devcube.yml'
workflow_dispatch:
schedule:
# Rebuild daily to get updated packages
- cron: '0 6 * * *'

env:
IMAGE_NAME: nvim-dev
IMAGE_NAME: devcube
IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}

jobs:
Expand Down Expand Up @@ -85,8 +95,8 @@ jobs:
- name: Build and push
uses: docker/build-push-action@v7
with:
context: dot_files/nvim
file: dot_files/nvim/Containerfile
context: dot_files
file: dot_files/devcube/Containerfile
platforms: ${{ matrix.platform }}
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
Expand Down Expand Up @@ -129,12 +139,12 @@ jobs:

- name: Generate build summary
run: |
echo "## nvim-dev Image Built" >> $GITHUB_STEP_SUMMARY
echo "## devcube Image Built" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Image:** \`${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}:latest\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Usage" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "ujust nvim-setup # pull image + install the 'nvim' wrapper" >> $GITHUB_STEP_SUMMARY
echo "nvim # launch the AI-first editor" >> $GITHUB_STEP_SUMMARY
echo "ujust devcube-setup # pull image + install the 'devc' wrapper" >> $GITHUB_STEP_SUMMARY
echo "devc # launch the parallel-agent workspace (workmux)" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
5 changes: 4 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ hypercube/
│ │ ├── hyprlock.conf # Lock screen
│ │ ├── hypridle.conf # Idle management
│ │ └── hyprpaper.conf # Wallpaper
│ ├── devcube/ # devcube IDE image (Containerfile, devc wrapper)
│ ├── lazygit/ # Lazygit config
│ ├── nvim/ # Neovim/LazyVim setup
│ ├── nvim/ # Neovim/LazyVim config (baked into devcube)
│ ├── qt6ct/ # Qt6 theming
│ ├── workmux/ # workmux parallel-agent config (baked into devcube)
│ ├── zellij/ # zellij multiplexer config (baked into devcube)
│ ├── quickshell/ # App launcher
│ └── starship/ # Shell prompt
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
> Cloud-native development environment with vim keybindings

[![Build](https://github.com/binarypie-dev/hypercube/actions/workflows/build.yml/badge.svg)](https://github.com/binarypie-dev/hypercube/actions/workflows/build.yml)
[![nvim-dev](https://github.com/binarypie-dev/hypercube/actions/workflows/build-nvim-dev.yml/badge.svg)](https://github.com/binarypie-dev/hypercube/actions/workflows/build-nvim-dev.yml)
[![devcube](https://github.com/binarypie-dev/hypercube/actions/workflows/build-devcube.yml/badge.svg)](https://github.com/binarypie-dev/hypercube/actions/workflows/build-devcube.yml)
[![Copr](https://copr.fedorainfracloud.org/coprs/binarypie/hypercube/package/datacube/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/binarypie/hypercube/)
[![GHCR](https://img.shields.io/badge/GHCR-ghcr.io%2Fbinarypie--dev%2Fhypercube-blue)](https://ghcr.io/binarypie-dev/hypercube)

Expand Down
6 changes: 3 additions & 3 deletions build_files/hypercube/03-hypercube-configs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ source = /usr/share/hypercube/config/hypr/hyprland.conf

EOF

### Neovim - AI-first sandbox overrides
# The editor config + AI agents ship baked into the podman image
# (ujust nvim-setup). Users keep ONLY personal plugin overrides here; this
### Neovim - devcube sandbox overrides
# The editor config + AI agents ship baked into the devcube podman image
# (ujust devcube-setup). Users keep ONLY personal plugin overrides here; this
# directory is bind-mounted into the container's baked LazyVim config and
# layered on top of it.
mkdir -p /etc/skel/.config/hypercube/nvim/lua/plugins
Expand Down
2 changes: 1 addition & 1 deletion build_files/hypercube/99-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ REQUIRED_FILES=(
# DX config
"/etc/distrobox/distrobox.ini"
"/usr/share/ublue-os/just/60-hypercube.just"
"/usr/share/ublue-os/just/61-nvim.just"
"/usr/share/ublue-os/just/61-devcube.just"
)

for file in "${REQUIRED_FILES[@]}"; do
Expand Down
23 changes: 23 additions & 0 deletions dot_files/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Build context for the devcube image is dot_files/. Exclude everything by
# default and re-include only the dirs the Containerfile bakes, so the heavy
# desktop configs (hypr backgrounds, quickshell assets, ...) never enter the
# build context.
*
!devcube/
!nvim/
!fish/
!starship/
!zellij/
!workmux/

# Noise inside the kept dirs.
**/.git
**/.DS_Store
**/Thumbs.db
**/*.log
**/*.swp
**/*.swo
**/*~

# Neovim lock/runtime data shouldn't be baked (mounted/managed at runtime).
nvim/lazy-lock.json
48 changes: 36 additions & 12 deletions dot_files/nvim/Containerfile → dot_files/devcube/Containerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# Hypercube AI-first Neovim sandbox
# Hypercube devcube — containerized IDE + parallel-agent orchestration
#
# A self-contained, portable podman image: LazyVim (baked in), the full dev
# toolchain (LSPs/formatters/linters), and AI coding agents (Claude Code, OpenAI
# Codex, Antigravity, GitHub CLI). Agents are launched from inside nvim.
# A self-contained, portable podman image: Neovim/LazyVim (baked in), the full
# dev toolchain (LSPs/formatters/linters), AI coding agents (Claude Code, OpenAI
# Codex, Antigravity, GitHub CLI), plus zellij + workmux for running multiple
# agents in parallel (each in its own git worktree) and a fish + starship shell.
#
# Build: podman build -t nvim-dev .
# Run: podman run --rm -it nvim-dev (see scripts/sandbox.sh for mounts)
# The build context is the parent dot_files/ dir so the fish/starship/zellij/
# workmux/nvim configs (top-level dotfiles) can be baked in.
#
# Build: cd dot_files && podman build -t devcube -f devcube/Containerfile .
# Run: devc (see devcube/scripts/devcube.sh for mounts + dispatch)

FROM registry.fedoraproject.org/fedora-toolbox:44

Expand Down Expand Up @@ -131,11 +135,17 @@ RUN brew install \
# =============================================================================
# LAYER 6: Infrastructure tools via Homebrew
# =============================================================================
# zellij (terminal multiplexer) + workmux (git-worktree -> multiplexer
# orchestration; a brew tap, auto-tapped by the fully-qualified name) power the
# parallel-agent workflow. starship renders the fish prompt baked in below.
RUN brew install \
opentofu \
helm \
sqlfluff \
fish
fish \
starship \
zellij \
raine/workmux/workmux

# =============================================================================
# LAYER 7: Rust toolchain (as linuxbrew user)
Expand Down Expand Up @@ -251,21 +261,35 @@ RUN mkdir -p /etc/profile.d /etc/fish/conf.d \
# The full LazyVim config is baked into $HOME/.config/nvim. Personal overrides
# are bind-mounted at runtime from the host (~/.config/hypercube/nvim) and
# layered on top via the runtimepath (see lua/config/lazy.lua).
COPY config/ /root/.config/nvim/
# NOTE: the build context is dot_files/, so the nvim config lives under nvim/.
COPY nvim/config/ /root/.config/nvim/

# Pre-install all plugins + build treesitter parsers so first launch is fast and
# offline. HOME=/root and PATH already include the brew nvim binary.
RUN nvim --headless "+Lazy! sync" +qa

# =============================================================================
# LAYER 14b: Bake the shell / multiplexer / orchestrator configs
# =============================================================================
# fish + starship give a good in-container shell/prompt; zellij + workmux drive
# the parallel-agent workflow. These seed into the persisted home volume on
# first run (podman copy-up), like the nvim config above. starship.toml lands at
# the exact path dot_files/fish/config.fish hardcodes for STARSHIP_CONFIG, so
# fish needs no edits (and it lives outside /root, so it's always present).
COPY fish/ /root/.config/fish/
COPY zellij/ /root/.config/zellij/
COPY workmux/ /root/.config/workmux/
COPY starship/ /usr/share/hypercube/config/starship/

# =============================================================================
# LAYER 15: Entrypoint
# =============================================================================
COPY entrypoint.sh /usr/local/bin/hypercube-nvim-entrypoint
RUN chmod +x /usr/local/bin/hypercube-nvim-entrypoint
ENTRYPOINT ["/usr/local/bin/hypercube-nvim-entrypoint"]
COPY devcube/entrypoint.sh /usr/local/bin/devcube-entrypoint
RUN chmod +x /usr/local/bin/devcube-entrypoint
ENTRYPOINT ["/usr/local/bin/devcube-entrypoint"]
CMD ["nvim"]

# Labels for GitHub Container Registry
LABEL org.opencontainers.image.source="https://github.com/binarypie/hypercube"
LABEL org.opencontainers.image.description="AI-first Neovim sandbox: LazyVim + dev toolchain + Claude Code, Codex, Antigravity, gh"
LABEL org.opencontainers.image.description="devcube: containerized IDE (Neovim/LazyVim + dev toolchain + Claude Code, Codex, Antigravity, gh) with zellij + workmux parallel-agent orchestration"
LABEL org.opencontainers.image.licenses="MIT"
48 changes: 27 additions & 21 deletions dot_files/nvim/Justfile → dot_files/devcube/Justfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# Hypercube Neovim sandbox — local development and testing commands
# Hypercube devcube — local development and testing commands
#
# The build context is the parent dot_files/ dir (so fish/starship/zellij/
# workmux/nvim configs can be baked), hence `-f Containerfile ..` below.

local_image := "localhost/nvim-dev"
remote_image := "ghcr.io/binarypie-dev/nvim-dev:latest"
# Throwaway volume so local testing never touches the real hypercube-nvim-home.
test_volume := "hypercube-nvim-test"
local_image := "localhost/devcube"
remote_image := "ghcr.io/binarypie-dev/devcube:latest"
# Throwaway volumes so local testing never touches the real per-project state.
test_volume := "hypercube-devcube-test"
test_wt_prefix := "devcube-wt-test"

# Default recipe - show help
default:
Expand All @@ -13,16 +17,16 @@ default:
# Image Building
# =============================================================================

# Build the container image locally
# Build the container image locally (context is the parent dot_files/ dir)
build:
@echo "Building nvim-dev image locally..."
podman build -t {{local_image}} .
@echo "Building devcube image locally..."
podman build -t {{local_image}} -f Containerfile ..
@echo "Done! Image: {{local_image}}"

# Build without cache
build-no-cache:
@echo "Building nvim-dev image (no cache)..."
podman build --no-cache -t {{local_image}} .
@echo "Building devcube image (no cache)..."
podman build --no-cache -t {{local_image}} -f Containerfile ..
@echo "Done! Image: {{local_image}}"

# Push to GHCR (requires: podman login ghcr.io)
Expand All @@ -34,30 +38,27 @@ push:
# Usage (against the LOCAL image)
# =============================================================================

# Launch the sandbox (nvim) from the local image, using a throwaway test volume
# Launch devcube from the local image (e.g. `just run` for workmux, `just run nvim`),
# using throwaway test volumes.
run *args:
HYPERCUBE_NVIM_IMAGE={{local_image}} HYPERCUBE_NVIM_VOLUME={{test_volume}} ./scripts/sandbox.sh {{args}}
DEVCUBE_IMAGE={{local_image}} DEVCUBE_VOLUME={{test_volume}} DEVCUBE_WT_PREFIX={{test_wt_prefix}} ./scripts/devcube.sh {{args}}

# Launch an agent directly (e.g. `just run-agent claude`) from the local image
# Launch a specific tool directly (e.g. `just run-agent claude`) from the local image
run-agent agent *args:
#!/usr/bin/bash
set -euo pipefail
link="$(mktemp -d)/{{agent}}"
ln -s "$(pwd)/scripts/sandbox.sh" "$link"
HYPERCUBE_NVIM_IMAGE={{local_image}} HYPERCUBE_NVIM_VOLUME={{test_volume}} "$link" {{args}}
DEVCUBE_IMAGE={{local_image}} DEVCUBE_VOLUME={{test_volume}} DEVCUBE_WT_PREFIX={{test_wt_prefix}} ./scripts/devcube.sh {{agent}} {{args}}

# Open a shell in the local image
shell:
podman run --rm -it --init --user 0:0 --security-opt label=disable \
-e HYPERCUBE_NVIM=1 -e TERM \
-e DEVCUBE=1 -e TERM \
-v {{test_volume}}:/root \
{{local_image}} bash

# =============================================================================
# Tests
# =============================================================================

# Verify the image: nvim config loads and the toolchain + AI CLIs are present
# Verify the image: nvim config loads and the toolchain + AI CLIs + orchestrators are present
test-build: build
@echo "Testing container..."
podman run --rm {{local_image}} nvim --headless +qa
Expand All @@ -70,6 +71,10 @@ test-build: build
podman run --rm {{local_image}} claude --version
podman run --rm {{local_image}} codex --version
podman run --rm {{local_image}} agy --version
podman run --rm {{local_image}} zellij --version
podman run --rm {{local_image}} workmux --version
podman run --rm {{local_image}} starship --version
podman run --rm {{local_image}} fish --version
@echo ""
@echo "All tests passed!"

Expand All @@ -81,6 +86,7 @@ test-build: build
clean-image:
-podman rmi {{local_image}}

# Remove the throwaway test volume
# Remove the throwaway test volumes (home + any per-project worktree volumes)
clean-volume:
-podman volume rm -f {{test_volume}}
-podman volume ls -q | grep '^{{test_wt_prefix}}-' | xargs -r podman volume rm -f
File renamed without changes.
Loading
Loading